unique_ptr
null 状態検出を備えた軽量のポインター クラスとして特別に設計されました (たとえば、オプション オブジェクトを表すユーティリティ クラスを追加する提案 (改訂 3) のオプションに記載されています) 。
そうは言っても、 operator*のドキュメントには次のように記載されているため、あなたが求めている機能はすでに整っています。
// may throw, e.g. if pointer defines a throwing operator*
typename std::add_lvalue_reference<T>::type operator*() const;
pointer
タイプは次のように定義されます。
std::remove_reference<Deleter>::type::pointer if that type exists, otherwise T*
したがって、カスタム デリーターを使用すると、null ポインターのチェックや例外のスローを含むオンザフライ操作を実行できます。
#include <iostream>
#include <memory>
struct Foo { // object to manage
Foo() { std::cout << "Foo ctor\n"; }
Foo(const Foo&) { std::cout << "Foo copy ctor\n"; }
Foo(Foo&&) { std::cout << "Foo move ctor\n"; }
~Foo() { std::cout << "~Foo dtor\n"; }
};
struct Exception {};
struct InternalPtr {
Foo *ptr = nullptr;
InternalPtr(Foo *p) : ptr(p) {}
InternalPtr() = default;
Foo& operator*() const {
std::cout << "Checking for a null pointer.." << std::endl;
if(ptr == nullptr)
throw Exception();
return *ptr;
}
bool operator != (Foo *p) {
if(p != ptr)
return false;
else
return true;
}
void cleanup() {
if(ptr != nullptr)
delete ptr;
}
};
struct D { // deleter
using pointer = InternalPtr;
D() {};
D(const D&) { std::cout << "D copy ctor\n"; }
D(D&) { std::cout << "D non-const copy ctor\n";}
D(D&&) { std::cout << "D move ctor \n"; }
void operator()(InternalPtr& p) const {
std::cout << "D is deleting a Foo\n";
p.cleanup();
};
};
int main()
{
std::unique_ptr<Foo, D> up(nullptr, D()); // deleter is moved
try {
auto& e = *up;
} catch(Exception&) {
std::cout << "null pointer exception detected" << std::endl;
}
}
Live Example
完全を期すために、2 つの追加の代替手段/回避策を投稿します。
unique_ptr
ビアのポインタチェックoperator bool
#include <iostream>
#include <memory>
int main()
{
std::unique_ptr<int> ptr(new int(42));
if (ptr) std::cout << "before reset, ptr is: " << *ptr << '\n';
ptr.reset();
if (ptr) std::cout << "after reset, ptr is: " << *ptr << '\n';
}
(これはおそらく、この問題に対処するための最も巧妙な方法です)
別の解決策は、面倒ですが、例外処理を処理するラッパータイプを使用することです