19

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

#include <string>
#include <vector>
#include <iostream>

class Test final {
public:
  Test(const std::string& s)
    : s_(s) {
    std::cout << "constructing: " << s_ << std::endl;
  }
#ifdef NO_MOVE
private:
  Test(const Test& t) = delete;
  Test(Test&& t) = delete;
#else
public:
  Test(const Test& t)
    : s_(t.s_) {
    std::cout << "copying: " << s_ << std::endl;
  };
  Test(Test&& t)
    : s_(std::move(t.s_)) {
    std::cout << "moving: " << s_ << std::endl;
  };
#endif
private:
  std::string s_;
};

int main() {
  std::vector<Test> v;
  v.emplace_back("emplace_back");
}

移動コンストラクターが許可されている場合、以下が発生します。

[matt test] g++ -std=c++11 main.cpp && ./a.out
constructing: emplace_back

ただし、moveコンストラクターが削除された場合:

[matt test] g++ -std=c++11 main.cpp -DNO_MOVE && ./a.out
/usr/lib/gcc/x86_64-redhat-linux/4.7.2/../../../../include/c++/4.7.2/bits/stl_construct.h: In instantiation of ‘void std::_Construct(_T1*, _Args&& ...) [with _T1 = Test; _Args = {Test}]’:
/usr/lib/gcc/x86_64-redhat-linux/4.7.2/../../../../include/c++/4.7.2/bits/stl_uninitialized.h:77:3:   required from ‘static _ForwardIterator std::__uninitialized_copy<_TrivialValueTypes>::__uninit_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = std::move_iterator<Test*>; _ForwardIterator = Test*; bool _TrivialValueTypes = false]’
/usr/lib/gcc/x86_64-redhat-linux/4.7.2/../../../../include/c++/4.7.2/bits/stl_uninitialized.h:119:41:   required from ‘_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = std::move_iterator<Test*>; _ForwardIterator = Test*]’
/usr/lib/gcc/x86_64-redhat-linux/4.7.2/../../../../include/c++/4.7.2/bits/stl_uninitialized.h:260:63:   required from ‘_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, std::allocator<_Tp>&) [with _InputIterator = std::move_iterator<Test*>; _ForwardIterator = Test*; _Tp = Test]’
/usr/lib/gcc/x86_64-redhat-linux/4.7.2/../../../../include/c++/4.7.2/bits/stl_uninitialized.h:283:69:   required from ‘_ForwardIterator std::__uninitialized_move_if_noexcept_a(_InputIterator, _InputIterator, _ForwardIterator, _Allocator&) [with _InputIterator = Test*; _ForwardIterator = Test*; _Allocator = std::allocator<Test>]’
/usr/lib/gcc/x86_64-redhat-linux/4.7.2/../../../../include/c++/4.7.2/bits/vector.tcc:410:6:   required from ‘void std::vector<_Tp, _Alloc>::_M_emplace_back_aux(_Args&& ...) [with _Args = {const char (&)[13]}; _Tp = Test; _Alloc = std::allocator<Test>]’
/usr/lib/gcc/x86_64-redhat-linux/4.7.2/../../../../include/c++/4.7.2/bits/vector.tcc:102:4:   required from ‘void std::vector<_Tp, _Alloc>::emplace_back(_Args&& ...) [with _Args = {const char (&)[13]}; _Tp = Test; _Alloc = std::allocator<Test>]’
main.cpp:32:32:   required from here
main.cpp:14:3: error: ‘Test::Test(Test&&)’ is private
In file included from /usr/lib/gcc/x86_64-redhat-linux/4.7.2/../../../../include/c++/4.7.2/vector:63:0,
                 from main.cpp:2:
/usr/lib/gcc/x86_64-redhat-linux/4.7.2/../../../../include/c++/4.7.2/bits/stl_construct.h:77:7: error: within this context
/usr/lib/gcc/x86_64-redhat-linux/4.7.2/../../../../include/c++/4.7.2/bits/stl_construct.h:77:7: error: use of deleted function ‘Test::Test(Test&&)’
main.cpp:14:3: error: declared here

ただし、emplace_backは移動コンストラクターを使用しません。このインスタンスで初期化に移動コンストラクターが必要なのはなぜですか?

4

2 に答える 2

24

質問後のコメントで指定されているとおり。emplace_backオペレーターはコンテナーのメモリーを再割り振りする必要がある場合があるため、テンプレート・vectorタイプはコピーまたは移動して構築可能である必要があります。

新しいオブジェクトにメモリを割り当てることが問題になるのは、引数の転送ではありません。

于 2013-03-25T13:41:24.763 に答える
1

ベクトルにスペースがない場合は、新しいスペースを割り当ててそこにすべてを移動する必要があります。オブジェクト(ベクトル内)に含まれる、または所有するリソースのコピーを回避するには、移動が必要です。

タイプのベクトルの場合Test

Test object(original)--->resource on heap
Test object(relocated with move constructor)------>resource on heap
Test object(relocated with copy constructor)------>copy of resource on heap
于 2013-03-25T13:42:13.070 に答える