为什么emplace_back需要移动构造函数

时间:2022-02-22 04:15:21

I have the following code:

我有以下代码:

#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");
}

When a move constructor is allowed, the following occurs:

当允许移动构造函数时,会发生以下情况:

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

However, if the move constructor is removed:

但是,如果删除了移动构造函数:

[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

But the emplace_back doesn't use the move constructor. Why does the initialization require a move constructor in this instance?

但是emplace_back不使用移动构造函数。为什么初始化需要在这个实例中使用移动构造函数?

2 个解决方案

#1


22  

As specified in the comment after the question. The emplace_back operator may need to reallocate the containers memory and as such the vector template type needs to be either copy or move constructable.

正如问题后的评论中所指定的那样。 emplace_back运算符可能需要重新分配容器内存,因此向量模板类型需要是复制或移动可构造的。

It's not the forwarding of the arguments that is the issue it is the allocating of memory for the new object.

它不是转发参数,而是为新对象分配内存的问题。

#2


1  

If there is no space in the vector then it should allocate new space and move everything there and to avoid copy of the resource contained or owned by the objects(inside vector) move is required

如果向量中没有空格,那么它应该分配新空间并将所有内容移动到那里并避免复制对象所包含或拥有的资源(内部向量)移动是必需的

For vector of type 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

#1


22  

As specified in the comment after the question. The emplace_back operator may need to reallocate the containers memory and as such the vector template type needs to be either copy or move constructable.

正如问题后的评论中所指定的那样。 emplace_back运算符可能需要重新分配容器内存,因此向量模板类型需要是复制或移动可构造的。

It's not the forwarding of the arguments that is the issue it is the allocating of memory for the new object.

它不是转发参数,而是为新对象分配内存的问题。

#2


1  

If there is no space in the vector then it should allocate new space and move everything there and to avoid copy of the resource contained or owned by the objects(inside vector) move is required

如果向量中没有空格,那么它应该分配新空间并将所有内容移动到那里并避免复制对象所包含或拥有的资源(内部向量)移动是必需的

For vector of type 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