Boost.Optionalを使って、NULLポインタが呼び出し不能になるようにする

IL360 様の投稿記事、[NULLでないポインタは実体がなくても呼び出し可能](http://qiita.com/IL360/items/03c7568856e3be0d15eb)は、大変参考になりました。ありがとうございます。そこで、なんとか回避策を考えてみることにしました。

#普通にスマートポインタを使う
とりあえず、普通にスマートポインタを使って、NULL（C++11以降ではnullptr）なポインタを呼び出し不能にできないか試してみます。

```
#include <iostream>
#include <memory>

struct Test {
    ~Test()
    {
        std::cout << "called destructor" << std::endl;
    }

    void func()
    {
        std::cout << "Hello, World!" << std::endl;
    }
};

int main()
{
    auto pT(std::make_unique<Test>());  // C++14を想定しています
    pT->func();                         // Hello, World!と出力
    pT.reset();                         // ここでTestクラスのデストラクタが呼び出される
    if (!pT)
        // pTは確かにリソースを保持していないのに、、、
        std::cout << "pT doesn't have resource" << std::endl;
    pT->func();                         // ここで、Hello, Worldと出力される…
}
```

このコードをコンパイルして実行すると、

Hello, World!
called destructor
pT doesn't have resource
Hello, World!

などと表示され、リソースを保持していないスマートポインタに対しても、メンバ関数が呼び出せてしまいます。いろいろ試しましたが、結局これを回避するには、スマートポインタのチェックが必要のようです。

```
// （クラス定義等は省略）

int main()
{
    auto pT(std::make_unique<Test>());  // C++14を想定しています
    pT->func();                         // Hello, World!と出力
    pT.reset();                         // ここでTestクラスのデストラクタが呼び出される
    if (!pT)
        // pTは確かにリソースを保持していない
        std::cout << "pT doesn't have resource" << std::endl;
    if (pT)
        pT->func();                     // ここには来ない
}
```

このコードをコンパイルして実行すると、

Hello, World!
called destructor
pT doesn't have resource

となり、期待した動作になります。しかし、いちいちそのスマートポインタがリソースを保持していないかどうかのチェックをするのは非常に面倒ですし、チェック忘れがバグの温床にもなりがちです。

#Boost.Optionalを使う
もし「ポインタ」でなくて、「ポインタっぽいもの」で良いのならば、Boost.Optionalが使えます。例えば、

```
#include <iostream>
#include <boost/optional.hpp>
#include <boost/utility/in_place_factory.hpp>

struct Test {
    ~Test()
    {
        std::cout << "called destructor" << std::endl;
    }

    void func()
    {
        std::cout << "Hello, World!" << std::endl;
    }
};

int main()
{
    boost::optional<Test> pT(boost::in_place());
    pT->func();                                 // Hello, World!と出力
    pT = boost::none;                           // ここでTestクラスのデストラクタが呼び出される
    if (!pT)
        // pTは確かにリソースを保持していない
        std::cout << "pT doesn't have resource" << std::endl;
    pT->func();                                 // ここで実行時エラー
}
```

このコードをClang 3.5でコンパイルして実行してみると、

Hello, World!
called destructor
pT doesn't have resource
a.out: /home/dc1394/oss/boost_1_57_0/boost/optional/optional.hpp:1002: pointer_type boost::optional<Test>::operator->() [T = Test]: Assertion `this->is_initialized()' failed.
中止

と出力され、実行時エラーで止まってくれます（g++ 4.9.2でも試しましたが、同様に止まってくれました）。これは期待した動作です。

ただし、Boost.Optionalは、オブジェクトがフリーストア（ヒープ）に配置されず、スタックに配置されます。さらにポインタと違い、operator=で、オブジェクトがディープコピーされます。

実際、以下のコードをコンパイルして実行してみると、

```
#include <iostream>
#include <boost/optional.hpp>
#include <boost/utility/in_place_factory.hpp>

struct Test {};

int main()
{
    boost::optional<Test> pT(boost::in_place());
    std::cout << "address of pT  = " << &(*pT) << std::endl;
    auto pT2 = pT;
    std::cout << "address of pT2 = " << &(*pT2) << std::endl;
}
```

address of pT  = 0x7fffe5ed4b91
address of pT2 = 0x7fffe5ed4ba1

となり、オブジェクトがディープコピーされていることが確認できます。
さらに、Boost.Optionalはポリモーフィズムをサポートしません。つまり、

```
#include <iostream>
#include <boost/optional.hpp>
#include <boost/utility/in_place_factory.hpp>

struct Base {};

struct Derived : Base {};

int main()
{
    boost::optional<Derived> pDeriv(boost::in_place());
    boost::optional<Base> pBase = pDeriv;               // コンパイルエラー
}
```

このコードはコンパイルエラーとなります。
以上の制限を理解した上で、ポインタの代替としてBoost.Optionalを使うのは、理にかなっていると考えます。

#まとめ
C++では、スマートポインタを使っても、リソースを保持していないポインタのメンバにアクセスできてしまいます。
Boost.Optionalは、制約が厳しいですが、ポインタの代替として魅力的だと思います。