6

全て、

初期化子リスト形式を使用してウィジェット配列をインスタンス化すると、メンバー変数ウィジェット インスタンスを指すネイキッド ポインターがコンパイルされますが、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 スタイルのイテレーションがオブジェクトのコピーを行っていることは自明だと思います。

4

2 に答える 2

8

C++11 標準のパラグラフ 8.5.1/2 によると:

8.5.4 で指定されているように、集合体が初期化子リストによって初期化される場合、初期化子リストの要素は、添字またはメンバーの昇順で、集合体のメンバーの初期化子として取得されます。各メンバーは、対応する初期化句からコピー初期化されます。[...]

次に、各要素のコピー初期化には、目的の型の一時的な作成が含まれます。これは、配列の要素のコピー構築に使用されます。

ただし、クラスには、型が のインスタンスであるメンバーが含まれておりunique_ptr、これはコピーできません。これにより、クラスもコピーできなくなります。

さらに、あなたのクラスunique_ptrmoveableですが、明示的に定義されたデストラクタの存在によって、コンパイラによるムーブ コンストラクタの暗黙的な生成が抑制されるため、クラスはそうではありません。そうでない場合 (つまり、クラスのムーブ コンストラクターを明示的に定義した場合) は、コピー初期化が機能します (8.5/15 を参照)。

の定義をWFactory次のように変更してみてください。

class WFactory
{
public:
    WFactory(const int i)   : _w(new W1()) {}
    WFactory(const char* s) : _w(new W2()) {}
    WFactory(WFactory&& f) : _w(std::move(f._w)) {}
    ~WFactory() { _w.reset(nullptr); }
private:
    std::unique_ptr<Widget> _w;
};

int main()
{
    std::unique_ptr<Widget> a(new W1());
    WFactory wf[] { 4, "msg" };          // OK
}
于 2013-02-22T20:29:43.767 に答える