简体   繁体   中英

why does emplace_back need move constructor

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?

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.

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM