■
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を使用した。
スマートポインタは便利なだけに、ハマったときの解決策が分からなすぎて怖い。