std::map emplace without copying value
The arguments you pass to map::emplace
get forwarded to the constructor of map::value_type
, which is pair<const Key, Value>
. So you can use the piecewise construction constructor of std::pair
to avoid intermediate copies and moves.
std::map<int, Foo> m;
m.emplace(std::piecewise_construct,
std::forward_as_tuple(1),
std::forward_as_tuple(2.3, "hello"));
Live demo
Is it possible to do a no-copy emplace into map while using aggregate initialization?
You may exploit casts to indirect your construction
template<typename T>
struct tag { using type = T; };
template<typename F>
struct initializer
{
F f;
template<typename T>
operator T() &&
{
return std::forward<F>(f)(tag<T>{});
}
};
template<typename F>
initializer(F&&) -> initializer<F>;
template<typename... Args>
auto initpack(Args&&... args)
{
return initializer{[&](auto t) {
using Ret = typename decltype(t)::type;
return Ret{std::forward<Args>(args)...};
}};
}
And use it as
struct Foo
{
const int& intref_;
std::mutex mutex_;
};
void foo()
{
int i = 42;
std::map<int, Foo> m;
m.emplace(std::piecewise_construct,
std::forward_as_tuple(0),
std::forward_as_tuple(initpack(i)));
}
Note you can't prolong a temporary's lifetime by binding it to a non-stack reference.
How can I try_emplace a POD struct in a std::map?
Your first two attempts
dict.try_emplace(1, 2);
dict.try_emplace(1, 1, 2);
fail because you cannot use try_emplace
, emplace
etc. to initialize an aggregate from a list of values. Standard allocators construct the types in-place using ()
instead of {}
, which of course will fail for aggregates. See the answers to this question.
The third attempt
dict.try_emplace(1, {1, 2});
fails because a braced-init-list is not an expression, and doesn't have a type, so template argument deduction fails to deduce it as various
.
You can get try_emplace
to work by specifying you're constructing a various
instance
dict.try_emplace(1, various{1, 2});
Or add appropriate constructor(s) to various
, which will allow the first two attempts to work.
However, given that you're working with a map
containing builtin types, the easiest solution is to just use insert
instead of emplacement.
dict.insert({1, {1, 2}});
The map::insert
overload called above is std::pair<iterator,bool> insert(value_type&&)
, where value_type
is pair<const int, various>
. The nested braced-init-lists are deduced as value_type
by the overload resolution rules in over.match.list
, specifically the second bullet
If no viable initializer-list constructor is found, overload resolution is performed again, where the candidate functions are all the constructors of the class
T
and the argument list consists of the elements of the initializer list.
The pair(T1 const&, T2 const&)
constructor is selected.
How best to use emplace with std::map
Should you just pass the arguments of the constructor
Yes, because this is literally what all emplace()
functions are designed for. With insert()
, you have to construct an object, and then [usually] copy it into your container. And generally, if you're using a container, you're only constructing so you can put them into the container. As you can see in your tests, it's a bit of extra work.
emplace()
was designed to allow you to construct directly into the container. And you do so by providing constructor parameters to the emplace function. insert()
is used if you've already got an object and want to put it in a container.
I had a snarky comment that others have noted is worth explaining a bit more. If your class (which I'll call Foo
) has single parameter constructors, it may appear that you can do the same thing as emplace()
by just passing the single parameter to something like insert()
or push_back()
or any place that would take a Foo as a parameter. This is a 'feature' of the language where the compiler will implicitly construct a Foo
for you and use it. The problem is that under the hood, it's not doing the same thing. Where emplace()
will build your object directly in the container, faking it by taking advantage of a single parameter constructor still causes copies to be made. Another downside to consider is this implicit conversion. It can hurt readability of your code or worse, break things. This can be avoided by marking the constructor as explicit
.
How to create new entry in std::map without copying the entry value - no pointers
Use emplace
:
#include <map>
#include <string>
#include <tuple>
std::map<std::string, X> m;
m.emplace(std::piecewise_construct,
std::forward_as_tuple("nocopy"),
std::forward_as_tuple());
This generalizes to arbitrary consructor arguments for the new key value and mapped value, which you just stick into the respective forward_as_tuple
calls.
In C++17 this is a bit easier:
m.try_emplace("nocopy" /* mapped-value args here */);
Why does std::map emplace need a copy constructor on gcc?
This is not valid in C++11 as published.
The C++11 standard depicts two pair
constructors with two parameters:
pair(const T1& x, const T2& y);
template<class U, class V> pair(U&& x, V&& y);
If the first gets chosen, you are doomed for obvious reasons.
The second overload does not participate in overload resolution if, as relevant here, "V
is not implicitly convertible to second_type
". Here, V
is int
, second_type
is CMyClass
. Is int
implicitly convertible to CMyClass
? No, because the declaration CMyClass x = some_int;
is not well-formed, as in C++11 that declaration notionally constructs a CMyClass
temporary from some_int
and then moves it into x, but CMyClass
cannot be moved.
The extra overloads GCC added - as is allowed - have similar constraints.
C++17 substantially revamped the constraints on pair
's constructors, which has the side effect of allowing your code to work. Implementers treated this as a retroactive defect fix, which is why GCC 6 accepts your code.
Related Topics
C++ Fast Screenshots in Linux for Use with Opencv
Illegal Token on Right Side of ::
Boost Asio Single Threaded Performance
How True Is "Want Speed? Pass by Value"
How to Write Log Base(2) in C/C++
Using a Stl Map of Function Pointers
In C++, What Is a "Namespace Alias"
Overriding a Base's Overloaded Function in C++
Why Is There Not an Std::Is_Struct Type Trait
C-Style Strings as Template Arguments
Opencv Videocapture Lag Due to the Capture Buffer
Effective C++ Item 23 Prefer Non-Member Non-Friend Functions to Member Functions