2

私はこのコードを持っています:

#include <iostream>
#include <vector>

using namespace std;

class Foo{
public:
    Foo() noexcept {cout << "ctor" << endl;}
    Foo(const Foo&) noexcept {cout << "copy ctor" << endl;}
    Foo(Foo&&) noexcept {cout << "move ctor" << endl;}

    Foo& operator=(Foo&&) noexcept {cout << "move assn" << endl; return *this;}
    Foo& operator=(const Foo&) noexcept {cout << "copy assn" << endl; return *this;}

    ~Foo() noexcept {cout << "dtor" << endl;}
};


int main()
{   
    Foo foo;

    vector<Foo> v;
    v.push_back(std::move(foo)); 

    // comment the above 2 lines and replace by
    // vector<Foo> v{std::move(foo)}; 
}

g++ -std=c++11 --no-elide-constructors出力は私が期待するものです(フラグなしで同じ出力でコンパイルされます)

ctor
move ctor
dtor
dtor

ベクトルをpush_back直接初期化する代わりに、v

vector<Foo> v{std::move(foo)};

出力が得られる理由がわかりません:

1) (なし--no-elide-constructors)

ctor
move ctor
copy ctor
dtor
dtor
dtor

2) (と--no-elide-constructors)

ctor
move ctor
move ctor
copy ctor
dtor
dtor
dtor
dtor

最初のケースでは、なぜ copy ctor が呼び出されるのでしょうか? そして 2 番目のケースでは、コンパイラが省略を実行しない場合、move ctor が 2 回呼び出される理由がまったくわかりません。何か案は?

4

2 に答える 2

11
vector<Foo> v{std::move(foo)};

ここでは、 を受け取るベクター コンストラクターを呼び出していますstd::initializer_list。初期化子リストはconstその要素へのアクセスのみを許可するため、は各要素を から独自のストレージvectorにコピーする必要があります。initializer_listこれが、コピー コンストラクターの呼び出しの原因です。

§8.5.4 /5 より [dcl.init.list]

type のオブジェクトは、実装が type の要素のstd::initializer_list<E>一時配列を割り当てたかのように、初期化子リストから構築されます。ここで、 は初期化子リスト内の要素の数です。Nconst EN

https://tristanbrindle.com/posts/beware-copies-initializer-listも参照してください


を使用した追加の移動コンストラクター呼び出しについては、数日前に別の回答-fno-elide-constructorsで説明されました。g++ は、上で引用した同じセクションの標準に示されているan の実装例に対して、非常に文字通りのアプローチを取っているようです。initializer_list

同じ例を clang を使用してコンパイルすると、余分な move コンストラクター呼び出しが生成されません。

于 2014-07-17T00:41:23.907 に答える
3

コンテナは、例外が発生した場合でも使用可能なままであることを確認するために非常に懸命に努力します。この一環としてstd::move、クラスのムーブ コンストラクターが例外セーフである場合にのみ内部的に使用します。そうでない場合 (または判断できない場合) は、念のためコピーします。

正しい移動操作は

Foo(Foo&&) noexcept {cout << "move ctor" << endl;}
Foo& operator=(Foo&&) noexcept {cout << "move assn" << endl;}
于 2014-07-17T00:31:09.883 に答える