Consider the following program:
#include
#include
using namespace std;
struct T
{
int a;
double b;
string c;
};
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.
You can use the {}
syntax to initialize the new element:
V.emplace_back(T{42, 3.14, "foo"});
This may or may not be optimized, but it should be.
You have to define a constructor for this to work, note that with your code you can't even do:
T a(42, 3.14, "foo");
But this is what you need to have emplace work.
so just:
struct T {
...
T(int a_, double b_, string c_) a(a_), b(b_), c(c_) {}
}
will make it work the desired way.
This seems to be covered in 23.2.1/13.
First, definitions:
Given a container type X having an allocator_type identical to A and a value_type identical to T and given an lvalue m of type A, a pointer p of type T*, an expression v of type T, and an rvalue rv of type T, the following terms are defined.
Now, what makes it emplace-constructible:
T is EmplaceConstructible into X from args , for zero or more arguments args, means that the following expression is well-formed: allocator_traits::construct(m, p, args);
And finally a note about the default implementation of the construct call:
Note: A container calls allocator_traits::construct(m, p, args) to construct an element at p using args. The default construct in std::allocator will call ::new((void*)p) T(args), but specialized allocators may choose a different definition.
This pretty much tells us that for a default (and potentially the only) allocator scheme you must have defined a constructor with the proper number of arguments for the thing you're trying to emplace-construct into a container.
If you do not want to (or cannot) add a constructor, specialize allocator for T (or create your own allocator).
namespace std {
template<>
struct allocator<T> {
typedef T value_type;
value_type* allocate(size_t n) { return static_cast<value_type*>(::operator new(sizeof(value_type) * n)); }
void deallocate(value_type* p, size_t n) { return ::operator delete(static_cast<void*>(p)); }
template<class U, class... Args>
void construct(U* p, Args&&... args) { ::new(static_cast<void*>(p)) U{ std::forward<Args>(args)... }; }
};
}
Note: Member function construct shown above cannot compile with clang 3.1(Sorry, I don't know why). Try next one if you will use clang 3.1 (or other reasons).
void construct(T* p, int a, double b, const string& c) { ::new(static_cast<void*>(p)) T{ a, b, c }; }
You can create the struct T
instance and then move it to the vector:
V.push_back(std::move(T {42, 3.14, "foo"}));
you have to define a constructor for your type T
because it contains an std::string
which is not trivial.
moreover, it would be better to define (possible defaulted) move ctor/assign (because you have a movable std::string
as member) -- this would help to move your T
much more efficient...
or, just use T{...}
to call overloaded emplace_back()
as recommended in neighboug response... everything depends on your typical use cases...