2

たとえば、私はクラスを持っています

class A
{
public:
    // argument with default value is too long, any better way
    A(std::unique_ptr<int> data = std::unique_ptr<int>(new int(10))) 
        : mData(std::move(data))
    {}

    // Is r-value better? Is the following code okay?
    A(std::unique_ptr<int>&& data = std::unique_ptr<int>(new int(10)))
        : mData(data)
    {}

private:
    std::unique_ptr<int> mData;
};
4

1 に答える 1

4

一見すると、次のことができるように見えます。

A (std::unique_ptr<int> data = {new int(10)}) 
    : mData(std::move(data))
{}

中括弧の使用に注意してください (つまり、一様な初期化)。ただし、ポインターを受け入れるコンストラクターが として宣言されているため、これは機能しません(コンパイルされません) 。unique_ptrexplicit

あなたができるもう1つのことはこれです:

A (int * data = new int(10)) 
    : mData (data)
{}

つまり、通常のポインターを受け取り、そこからメンバーを構築します。また、そこから移動する必要もありません (std::moveそれでも推奨されます)。

これはコンパイルして機能しますが、渡されたポインターの所有権を引き継いでいるにもかかわらず (あなたはdeleteそれに行きます)、インターフェイスでこの動作を示していないという致命的な欠陥があります。そのため、この新しいインターフェースは以前のものよりも情報が少なくなります。

もう 1 つの方法は、次のようにショートカット関数テンプレートを作成することです。

template <typename T>
std::unique_ptr<T> uptr (T * v)
{
    return std::unique_ptr<T>(v);
}

そして、コンストラクターは次のようになります。

A(std::unique_ptr<int> data = uptr(new int(10))) 
    : mData(std::move(data))
{}

しかし、私の意見では、これはあまり改善されていません。

ただし、この特定のユースケースが問題全体である場合は、次のようにデフォルトのコンストラクターと単一引数のコンストラクターを定義してみませんか?

A () 
    : mData (new int (10))
{}

/*explicit*/ A (std::unique_ptr<int> data)
    : mData(std::move(data))
{}

これはより賢明です。(そこに置くexplicitことは良い考えと良い形ですが、あなたの問題とは関係がないのでコメントアウトしました。)

また、2 番目のコンストラクターは実際には何も移動しません。この場合、右辺値の参照型は、あなたが思っているようには機能しません。要するに、data名前があるので、もはや右辺値ではありませんが、その型は何かへの右辺値参照のままです。

于 2013-07-27T21:50:42.490 に答える