全て、
初期化子リスト形式を使用してウィジェット配列をインスタンス化すると、メンバー変数ウィジェット インスタンスを指すネイキッド ポインターがコンパイルされますが、std::unique_ptr<> gcc に変更すると、削除された関数に関するコンパイル エラーが発生します。
$ ウナメ -a
Linux .. 3.5.0-21-generic #32-Ubuntu SMP Tue Dec 11 18:51:59 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux
$ g++ --バージョン
g++ (Ubuntu/Linaro 4.7.2-5ubuntu1) 4.7.2
このコードでは、次のコンパイラ エラーが発生します。
#include <stdlib.h>
#include <memory>
class Widget
{
public:
Widget() {}
};
class W1 : public Widget
{
public:
W1() {}
};
class W2 : public Widget
{
public:
W2() {}
};
class WFactory
{
public:
WFactory(const int i) : _w(new W1()) {}
WFactory(const char* s) : _w(new W2()) {}
~WFactory() { _w.reset(nullptr); }
// ~WFactory() { delete _w; } <--- for naked ptr
private:
// NOTE: does not compile
std::unique_ptr<Widget> _w;
// NOTE: does compile
// Widget* _w;
};
int main()
{
std::unique_ptr<Widget> a(new W1()); // <--- compiles fine
WFactory wf[] { 4, "msg" }; // <--- compiler error using unique_ptr<>
}
エラー:
$ g++ -o unique_ptr -std=c++11 -Wall unique_ptr.cpp
unique_ptr.cpp: In function ‘int main()’:
unique_ptr.cpp:36:30: error: use of deleted function ‘WFactory::WFactory(const WFactory&)’
unique_ptr.cpp:22:7: note: ‘WFactory::WFactory(const WFactory&)’ is implicitly deleted because the default definition would be ill-formed:
unique_ptr.cpp:22:7: error: use of deleted function ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = Widget; _Dp = std::default_delete<Widget>; std::unique_ptr<_Tp, _Dp> = std::unique_ptr<Widget>]’
In file included from /usr/include/c++/4.7/memory:86:0,
from unique_ptr.cpp:2:
/usr/include/c++/4.7/bits/unique_ptr.h:262:7: error: declared here
unique_ptr.cpp:36:30: error: use of deleted function ‘WFactory::WFactory(const WFactory&)’
unique_ptr.cpp:36:14: warning: unused variable ‘wf’ [-Wunused-variable]
私は次のいずれかについて途方に暮れています。削除されたfcxnを生成する舞台裏のメカニズム。もっと簡単に言えば、ネイキッド ptr と比較して std::unique_ptr<> の表現力が制限されているように見える理由です。
私の質問は:
- パイロットエラー?
- コンパイルエラー?
- 意図したコードを変更して機能させることはできますか?
ありがとうございました。
編集 1
あなたの回答に基づいて、WFactory に次の変更を加えることができます。
(不道徳なコードとしてフラグが立てられました)
class WFactory
{
public:
WFactory(const WFactory& wf)
{
(const_cast<WFactory&>(wf)).moveto(_w);
}
WFactory(const int i) : _w(new W1()) {}
WFactory(const char* s) : _w(new W2()) {}
~WFactory() { _w.reset(nullptr); }
void moveto(std::unique_ptr<Widget>& w)
{
w = std::move(_w);
}
private:
std::unique_ptr<Widget> _w;
};
これで、プログラムがコンパイルされて実行されます。標準化関係者が何らかの理由で仕様を作成したことに感謝します。したがって、ptr の一意性を本当に強調したい場合に、私の結果を目前のケースの誠実な専門化として投稿します。
編集 2
Jonathan の返信に基づいて、次のコードは暗黙の move ctor を抑制しません。
class WFactory
{
public:
WFactory(const int i) : _w(new W1()) {}
WFactory(const char* s) : _w(new W2()) {}
private:
std::unique_ptr<Widget> _w;
};
全くありませんのでご注意ください~WFactory() {..}
。
おそらく ya-ans がありますが、Main() で wf[] に対して c++11 スタイルの反復を使用すると、no-copy-ctor-for-WFactory エラーが返されることがわかりました。あれは:
int Main()
..
WFactory wf[] { 4, "msg" };
for ( WFactory iwf : wf ) <---- compiler error again
// ..
for (unsigned i = 0; i < 2; ++i) <--- gcc happy
wf[i] // ..
}
新しい c++11 スタイルのイテレーションがオブジェクトのコピーを行っていることは自明だと思います。