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)));
ここには基本的に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)
}
値で渡します。これはコピーを作成することを意味します。それは非常にユニークではないでしょうか?
値を移動することもできますが、これはオブジェクトの所有権とその有効期間の制御を関数に渡すことを意味します。
オブジェクトの有効期間がMyFuncの呼び出しの有効期間にわたって存在することが保証されている場合は、ptr.get()
を介して生のポインタを渡すだけです。
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
にはまだポインターの所有権があります。
unique_ptr
を関数に渡せないのはなぜですか?
できますが、コピーではできません-std::unique_ptr<>
はコピー構築できないためです。
確かにこれは構造の主な目的ですか?
とりわけ、std::unique_ptr<>
は、(std::shared_ptr<>
とは対照的に)一意所有権を明確にマークするように設計されています。
そして最も奇妙なことに、なぜこれがそれを渡すのにOKな方法ですか?
その場合、コピー構成がないためです。
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人だけであることを保証するための意図的なコピーはありません。
unique_ptr
は一意の所有権であるため、引数として渡したい場合はtry
MyFunc(move(ptr));
ただし、その後のptr
のmain
の状態はnullptr
になります。