push_back emplace_back c++ c++11

emplace_back - c++ emplace back



¿Por qué emplace_back necesita mover constructor? (2)

Como se especifica en el comentario después de la pregunta. El operador emplace_back puede necesitar reasignar la memoria de los contenedores y, como tal, el tipo de plantilla vector debe ser emplace_back o emplace_back .

No es el reenvío de los argumentos que es el problema, es la asignación de memoria para el nuevo objeto.

Tengo el siguiente código:

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

Cuando se permite un constructor de movimiento, ocurre lo siguiente:

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

Sin embargo, si se quita el constructor de movimiento:

[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

Pero el emplace_back no usa el constructor de movimiento. ¿Por qué la inicialización requiere un constructor de movimiento en esta instancia?


Si no hay espacio en el vector, entonces debe asignar un nuevo espacio y mover todo allí y para evitar la copia del recurso contenido o propiedad de los objetos (dentro del vector), se requiere el movimiento.

Para vectores de tipo 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