■
unique_ptrを知ってから大変重宝している。
ほぼコスト0なのにdeleteをいちいち書かずに済むのでまさにスマートなポインタ。
が、しかし、見えないが故にエラーが出ると厄介だ。
次のようなプログラムを書いた。
Dataクラスにunique_ptrで確保したメモリがありそこにデータを入れる。
それをvectorにいれてデータ配列を作ろうとした。よくありそうな場面だ。
#include <memory>
#include <vector>
class Data
{
public:
  std::unique_ptr<char> Buffer;
  size_t Size;
  Data(char* _buf, size_t size)
    : Buffer(new char [size])
    , Size(size)
  {
    memcpy(Buffer.get(), _buf, size);
  };
};
int main()
{
  std::vector<Data> list;
  const int MEM_SIZE = 128;
  std::unique_ptr<char> mem(new char [MEM_SIZE]);
  Data d(mem.get(), MEM_SIZE);
  list.push_back(d);
 
  return 0;
}
しかしこれをコンパイルしたところ次のエラーが表示された。(Visual Studio 2012)
error C2248: 'std::unique_ptr<_Ty>::unique_ptr' : private メンバー (クラス 'std::unique_ptr<_Ty>' で宣言されている) にアクセスできません。
ネットで調べてみると、次のページがヒントになった。
http://stackoverflow.com/questions/22788275/stdvectorstdunique-ptrint-does-not-compile
どうやらコピーコンストラクタに原因がありそうだということだが、一体どこから呼びだそうとしているのか、地道に一行ずつコメントアウトして調べていくとpush_back()が原因だとわかった。(すぐに気付きたかった)
vectorにpuch_backで要素を入れる際、要素をコピーして渡す。その時、コピーコンストラクタが働く。そして、今回のDataクラスにはunique_ptrで確保されたメンバ変数がある。unique_ptrは代入不可・コピー不可なので、デフォルトコピーコンストラクタではコピーすることができず、上記のエラーが発生したということだった。
原因が分かったところで、Dataクラスにコピーコンストラクタを実装したところコンパイルに成功した。
  Data(const Data& rhs)
    : Buffer(new char [rhs.Size])
    , Size(rhs.Size)
  {
    // Buffer = std::move(d.Buffer);
    memcpy(Buffer.get(), rhs.Buffer.get(), Size);
  }
unique_ptrを移動させる定石であるmove関数はここでは使えない。引数がconstなので変更を加えることができないためだ。
ということで、昔ながらのmemcpyを使用した。
スマートポインタは便利なだけに、ハマったときの解決策が分からなすぎて怖い。