2

N2812は、値パラメーターとしてaが指定されているイントロダクションの例です。unique_ptr

void push_back2(
  std::list<std::unique_ptr<int>>& l, std::unique_ptr<int> a)
{
  l.push_back(a); // oops: moves from the lvalue 'a', silently!
  l.push_back(a); // oops: 'a' no longer has its original value
}

この論文では、RValue/LValue オーバーロードの解決に関する問題について説明していますが、それは私の主張ではありません。

引数std::unique_ptr<int> a を値で指定してもコンパイラ エラーが発生しないのだろうか? それはそれをコピーしますよね?そして、それは許可されていませんunique_ptr

論文がかなり古いことは承知しておりunique_ptr、それ以来 の定義が変更されている可能性があります。しかし、それは単なるタイプミスであり、作者はstd::unique_ptr<int> &a代わりに書きたかったのでしょうか?

私のgcc 4.7.0は私に同意しますが、それは証拠ではありません:-)

void push_back2( std::list<std::unique_ptr<int>>&, std::unique_ptr<int> ) { };
int main() {
  list<unique_ptr<int>> lst;
  unique_ptr<int> num { new int{4} };
  push_back2(lst, num); //ERR: use of deleted function
}
4

3 に答える 3

9

パラメータを値で取得しても問題はありません。コピーを使用してパラメーターを初期化しようとすると、その関数が削除されるため、コンパイラ エラーが発生することは間違いありません。ただし、引数として右辺値を指定することで、値パラメーターを初期化できます。例えば:

std::unique_ptr<int> myPtr{ /* ... */ }
std::list<std::unique_ptr<int>> elems;
push_back2(elems, myPtr);            // Error, as you've noted
push_back2(elems, std::move(myPtr)); // Fine, uses move constructor to initialize

この構文は、ポインターを関数に渡すことを明示的に示す必要があるという点で優れています。

の中push_back2に入ると、存在しないコピー コンストラクターを使用しようとするため、push_backを取り込むことができなくなります。これを修正するには、再度unique_ptr使用する必要があります。std::move

void push_back2(
  std::list<std::unique_ptr<int>>& l, std::unique_ptr<int> a)
{
  l.push_back(std::move(a)); // Fine, moves a
  l.push_back(std::move(a)); // Well that was dumb, but you asked for it!
}

私はあなたの質問を正しく解釈し、これがあなたが探しているものであることを願っています...他に明確にすることができるものがあれば教えてください!

于 2011-08-21T21:16:55.620 に答える
3

行動に関するあなたの知識と仮定は正しいです。

この論文の例は、概念のある C++ と概念のない C++ という 2 つの言語を混同しているため、混乱を招きます。この論文の偽りの言語では、required のlistpush_backCopyConstructibleは SFINAE で取り除かれ、requiring のオーバーロードだけが残りMoveConstructibleます。そのようなlist設計では左辺値が右辺値参照にバインドできるという古いルールを使用すると、push_back暗黙的にa2 回から移動します。

list実際にこのように振る舞う危険はまったくありませんでした。const value_type&作成者は、とがオーバーロードされていない状況を設定しようとしvalue_type&&ていただけvalue_type&&で、オーバーロード セットにしかありませんでした。

于 2011-08-21T21:36:50.700 に答える
0

関数の戻り値など、右辺値によって提供できます。

unique_ptr<int> make_unique() {
    return unique_ptr<int>(new int);
}
int main() {
    list<unique_ptr<int>> lst;
    lst.push_back(make_unique());
}

さらに、明示的std::moveにリストに入れることができます。

于 2011-08-21T21:17:51.787 に答える