Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++11 emplace_back on vector<struct>?

Tags:

c++

c++11

Consider the following program:

#include <string> #include <vector>  using namespace std;  struct T {     int a;     double b;     string c; };  vector<T> V;  int main() {     V.emplace_back(42, 3.14, "foo"); } 

It doesn't work:

$ g++ -std=gnu++11 ./test.cpp In file included from /usr/include/c++/4.7/x86_64-linux-gnu/bits/c++allocator.h:34:0,                  from /usr/include/c++/4.7/bits/allocator.h:48,                  from /usr/include/c++/4.7/string:43,                  from ./test.cpp:1: /usr/include/c++/4.7/ext/new_allocator.h: In instantiation of ‘void __gnu_cxx::new_allocator<_Tp>::construct(_Up*, _Args&& ...) [with _Up = T; _Args = {int, double, const char (&)[4]}; _Tp = T]’: /usr/include/c++/4.7/bits/alloc_traits.h:253:4:   required from ‘static typename std::enable_if<std::allocator_traits<_Alloc>::__construct_helper<_Tp, _Args>::value, void>::type std::allocator_traits<_Alloc>::_S_construct(_Alloc&, _Tp*, _Args&& ...) [with _Tp = T; _Args = {int, double, const char (&)[4]}; _Alloc = std::allocator<T>; typename std::enable_if<std::allocator_traits<_Alloc>::__construct_helper<_Tp, _Args>::value, void>::type = void]’ /usr/include/c++/4.7/bits/alloc_traits.h:390:4:   required from ‘static void std::allocator_traits<_Alloc>::construct(_Alloc&, _Tp*, _Args&& ...) [with _Tp = T; _Args = {int, double, const char (&)[4]}; _Alloc = std::allocator<T>]’ /usr/include/c++/4.7/bits/vector.tcc:97:6:   required from ‘void std::vector<_Tp, _Alloc>::emplace_back(_Args&& ...) [with _Args = {int, double, const char (&)[4]}; _Tp = T; _Alloc = std::allocator<T>]’ ./test.cpp:17:32:   required from here /usr/include/c++/4.7/ext/new_allocator.h:110:4: error: no matching function for call to ‘T::T(int, double, const char [4])’ /usr/include/c++/4.7/ext/new_allocator.h:110:4: note: candidates are: ./test.cpp:6:8: note: T::T() ./test.cpp:6:8: note:   candidate expects 0 arguments, 3 provided ./test.cpp:6:8: note: T::T(const T&) ./test.cpp:6:8: note:   candidate expects 1 argument, 3 provided ./test.cpp:6:8: note: T::T(T&&) ./test.cpp:6:8: note:   candidate expects 1 argument, 3 provided 

What is the correct way to do this and why?

(Also tried single and double braces)

like image 551
Andrew Tomazos Avatar asked Dec 11 '12 02:12

Andrew Tomazos


People also ask

What is Emplace_back in vector?

C++ Vector Library - emplace_back() Function The C++ function std::vector::emplace_back() inserts new element at the end of vector. Reallocation happens if there is need of more space. This method increases container size by one.

Should I use Push_back or Emplace_back?

Specific use case for emplace_back : If you need to create a temporary object which will then be pushed into a container, use emplace_back instead of push_back . It will create the object in-place within the container. Notes: push_back in the above case will create a temporary object and move it into the container.

Why is Emplace_back faster than Push_back?

because emplace_back would construct the object immediately in the vector, while push_back , would first construct an anonymous object and then would copy it to the vector.

Does Emplace_back copy or move?

Calling emplace_back will call the move constructor of std::string when std::move is used, which could save on a copy (so long as that string isn't stored in a SSO buffer). Note that this is essentially the same as push_back in this case.


2 Answers

You need to explicitly define a ctor for the class:

#include <string> #include <vector>  using namespace std;  struct T {     int a;     double b;     string c;      T(int a, double b, string &&c)          : a(a)         , b(b)         , c(std::move(c))      {} };  vector<T> V;  int main() {     V.emplace_back(42, 3.14, "foo"); } 

The point of using emplace_back is to avoid creating a temporary object, which is then copied (or moved) to the destination. While it is also possible to create a temporary object, then pass that to emplace_back, it defeats (at least most of) the purpose. What you want to do is pass individual arguments, then let emplace_back invoke the ctor with those arguments to create the object in place.

like image 123
Jerry Coffin Avatar answered Sep 20 '22 02:09

Jerry Coffin


For anyone from the future, this behavior will be changed in C++20.

In other words, even though implementation internally will still call T(arg0, arg1, ...) it will be considered as regular T{arg0, arg1, ...} that you would expect.

like image 23
Red XIII Avatar answered Sep 22 '22 02:09

Red XIII