web-dev-qa-db-ja.com

std :: unique_ptrを関数に渡す方法

std::unique_ptrを関数に渡すにはどうすればよいですか?次のクラスがあるとしましょう:

class A
{
public:
    A(int val)
    {
        _val = val;
    }

    int GetVal() { return _val; }
private:
    int _val;
};

以下はコンパイルされません。

void MyFunc(unique_ptr<A> arg)
{
    cout << arg->GetVal() << endl;
}

int main(int argc, char* argv[])
{
    unique_ptr<A> ptr = unique_ptr<A>(new A(1234));
    MyFunc(ptr);

    return 0;
}

std::unique_ptrを関数に渡せないのはなぜですか?確かにこれは構造の主な目的ですか?または、C++委員会は生のCスタイルポインターにフォールバックし、次のように渡すことを意図していましたか。

MyFunc(&(*ptr)); 

そして最も奇妙なことに、なぜこれがそれを渡すのにOKな方法ですか?それは恐ろしく矛盾しているようです:

MyFunc(unique_ptr<A>(new A(1234)));
54
user3690202

ここには基本的に2つのオプションがあります。

参照渡しでスマートポインターを渡す

void MyFunc(unique_ptr<A> & arg)
{
    cout << arg->GetVal() << endl;
}

int main(int argc, char* argv[])
{
    unique_ptr<A> ptr = unique_ptr<A>(new A(1234));
    MyFunc(ptr);
}

スマートポインターを関数の引数に移動します

この場合、アサーションが保持されることに注意してください!

void MyFunc(unique_ptr<A> arg)
{
    cout << arg->GetVal() << endl;
}

int main(int argc, char* argv[])
{
    unique_ptr<A> ptr = unique_ptr<A>(new A(1234));
    MyFunc(move(ptr));
    assert(ptr == nullptr)
}
84
Bill Lynch

値で渡します。これはコピーを作成することを意味します。それは非常にユニークではないでしょうか?

値を移動することもできますが、これはオブジェクトの所有権とその有効期間の制御を関数に渡すことを意味します。

オブジェクトの有効期間がMyFuncの呼び出しの有効期間にわたって存在することが保証されている場合は、ptr.get()を介して生のポインタを渡すだけです。

19
Mark Tolonen

unique_ptrを関数に渡せないのはなぜですか?

unique_ptrには移動コンストラクターがありますが、コピーコンストラクターがないため、これを行うことはできません。標準に従って、移動コンストラクターが定義されているが、コピーコンストラクターが定義されていない場合、コピーコンストラクターは削除されます。

12.8クラスオブジェクトのコピーと移動

...

7クラス定義がコピーコンストラクターを明示的に宣言していない場合、コピーコンストラクターは暗黙的に宣言されます。クラス定義が移動コンストラクターまたは移動代入演算子を宣言する場合、暗黙的に宣言されたコピーコンストラクターは削除済みとして定義されます。

以下を使用して、unique_ptrを関数に渡すことができます。

void MyFunc(std::unique_ptr<A>& arg)
{
    cout << arg->GetVal() << endl;
}

あなたが持っているようにそれを使用してください:

または

void MyFunc(std::unique_ptr<A> arg)
{
    cout << arg->GetVal() << endl;
}

次のように使用します:

std::unique_ptr<A> ptr = std::unique_ptr<A>(new A(1234));
MyFunc(std::move(ptr));

重要な注意

2番目の方法を使用する場合、std::move(ptr)の呼び出しが返された後、ptrはポインターの所有権を持たないことに注意してください。

void MyFunc(std::unique_ptr<A>&& arg)は、両方が参照であるため、void MyFunc(std::unique_ptr<A>& arg)と同じ効果があります。

最初のケースでは、ptrの呼び出し後、MyFuncにはまだポインターの所有権があります。

13
R Sahu

unique_ptrを関数に渡せないのはなぜですか?

できますが、コピーではできません-std::unique_ptr<>はコピー構築できないためです。

確かにこれは構造の主な目的ですか?

とりわけ、std::unique_ptr<>は、(std::shared_ptr<>とは対照的に)一意所有権を明確にマークするように設計されています。

そして最も奇妙なことに、なぜこれがそれを渡すのにOKな方法ですか?

その場合、コピー構成がないためです。

4
Nielk

MyFuncは所有権を取得しないため、次のようにするとよいでしょう。

void MyFunc(const A* arg)
{
    assert(arg != nullptr); // or throw ?
    cout << arg->GetVal() << endl;
}

またはそれ以上

void MyFunc(const A& arg)
{
    cout << arg.GetVal() << endl;
}

本当に所有権を取得したい場合は、リソースを移動する必要があります。

std::unique_ptr<A> ptr = std::make_unique<A>(1234);
MyFunc(std::move(ptr));

または、r値参照を直接渡します。

MyFunc(std::make_unique<A>(1234));

std::unique_ptrには、所有者が1人だけであることを保証するための意図的なコピーはありません。

4
Jarod42

unique_ptrは一意の所有権であるため、引数として渡したい場合はtry

MyFunc(move(ptr));

ただし、その後のptrmainの状態はnullptrになります。

0
0x6773