How does boost::unordered_map.emplace(Args&&... args) work? - c++

According to the documentation it:
Inserts an object, constructed with
the arguments args, in the container
if and only if there is no element in
the container with an equivalent key.
But the only objects which can be inserted into an unordered_map have type std::pair<Key const, Mapped>(because both a key and a value are needed for an object to be inserted), which is known to take a constructor with exactly two arguments. So why does it use the variadic function form? Surely there is something I am totally not understanding about this.

See this SO article on emplace_back vs. push_back. Essentially, it allows an object to be constructed from the arguments passed into it without needing to create the object to be passed in first. It saves on overhead by removing a copy construction which normally happens as the result of creating objects to be inserted.
So you can get away with this:
unordered_map<int,int> foo;
foo.emplace(4, 5);
instead of
foo.insert(std::make_pair(4, 5));
Even better, (and if I'm not mistaken), you can go through this route:
struct Bar{
int x,y;
Bar(int _x, int _y) : x(_x), y(_y){}
};
unordered_map<int,Bar> baz;
baz.emplace(4, 5, 6);
And taken from the Wiki on C++0x:
Due to the nature of the wording of rvalue references, and to some modification to the wording for lvalue references (regular references), rvalue references allow developers to provide perfect function forwarding. When combined with variadic templates, this ability allows for function templates that can perfectly forward arguments to another function that takes those particular arguments. This is most useful for forwarding constructor parameters, to create factory functions that will automatically call the correct constructor for those particular arguments.
Which works in the following manner:
template<typename TypeToConstruct> struct SharedPtrAllocator {
template<typename ...Args> std::shared_ptr<TypeToConstruct> construct_with_shared_ptr(Args&&... params) {
return std::shared_ptr<TypeToConstruct>(new TypeToConstruct(std::forward<Args>(params)...));
}
}
Again, shamelessly stolen from the Wiki article mentioned above.

Now that the C++ Standard Library has integrated that part of Boost:
From http://en.cppreference.com
#include <iostream>
#include <utility>
#include <tuple>
#include <unordered_map>
int main(){
std::unordered_map<std::string, std::string> m;
// uses pair's piecewise constructor
m.emplace(std::piecewise_construct,
std::forward_as_tuple("c"),
std::forward_as_tuple(10, 'c'));
for (const auto &p : m) {
std::cout << p.first << " => " << p.second << '\n';
}
}
std::piecewise_construct is a constant that leaves no ambiguity about how the arguments will be used
The first tuple will be used to construct the key
The second to construct the value

Related

Use initializer list to create single item vector

I have a function func which is overloaded to take either a std::vector<Obj> argument or a Obj argument.
#include <vector>
#include <iostream>
class Obj {
int a = 6;
};
void func(const std::vector<Obj>& a) {
std::cout << "here" << std::endl;
}
void func(const Obj& a) {
std::cout << "there" << std::endl;
}
int main() {
Obj obj, obj2;
func({obj});
func({obj, obj2});
}
Actual output:
there
here
Expected output:
here
here
It seems {obj} doesn't initialize a vector, but rather an object. I guess there is some priority order when it comes to which type it initializes. How do I control it precisely?
(Examples compiled with g++ (Ubuntu 8.3.0-6ubuntu1) 8.3.0.)
I found a possible duplicate (c++11 single element vector initialization in a function call), although my question remains unanswered:
I understand that {obj} can resolve to an object rather a vector of a single element and the former takes priority. But is there a way to use {} to create a single item vector (so that foo resolves to the std::vector overload)? I could create a vector explicitly but {} seems nicer.
As mentioned in the linked question duplicate (the original) there is no way to force the resolution in favour of the overload taking std::initializer_list.
The original signatures (using int to simplify):
void func(const std::vector<int> &a);
void func(const int &a);
Since I have encountered this many times I typically do this:
func(std::vector<int>{10});
I am not aware of any shorter way of doing this because using actual type std::initializer_list that would do the same is even more verbose. But on the birght side it at least makes what you are doing perfectly clear since {10} is really ambiguous if not accompanied with the type.
You can't.
Excerpt (from here, emphasis mine):
"[...] if the initializer list has a single element of type E and
either T is not a reference type or its referenced type is
reference-related to E, the object or reference is initialized from
that element (by copy-initialization for copy-list-initialization, or by direct-initialization for direct-list-initialization)"
Therefore, in your linked example, {obj} will "decay" to obj and the overload will resolve to void func(const Obj& a).
As stated in the other answer, you can explicitely call func(std::vector {obj}) to call the vector overload instead.

Forwarding the same value to two or more functions

When using forwarding references, is it a bad idea to forward the
same value to more than one function? Consider the following piece of code:
template<typename Container>
constexpr auto
front(Container&& c)
-> typename Container::value_type
{ return std::forward<Container>(c).front(); }
template<typename Container>
constexpr auto
back(Container&& c)
-> typename Container::value_type
{ return std::forward<Container>(c).back(); }
template<typename Container>
constexpr auto
get_corner(Container&& c)
{
return do_something(front(std::forward<Container(c)),
back(std::forward<Container>(c));
}
If Container is an lvalue-reference, the function works just fine. However, I'm worrying about situations where rvalues are passed on to it, because the value would get invalidated once a move occurs. My doubt is: Is there a correct way to forward the container in that case, without losing the value category?
In general, it is not reasonable for the same function to forward the same parameter twice. Not unless it has specific knowledge of what the receiver of that forwarded parameter will do.
Remember: the behavior of std::forward can be equivalent to the behavior of std::move, depending on what parameter the user passed in. And the behavior of an xvalue will be contingent on how the receiving function processes it. If the receiver takes a non-const rvalue reference, it will likely move from that value if possible. That would leave you holding a moved-from object. If it takes a value, it will certainly move from it if the type supports it.
So unless you have specific knowledge of the expected behavior of the operations you are using, it is not safe to forward a parameter more than once.
There's actually no rvalue-reference version of std::begin - we just have (setting aside constexpr and return values):
template <class C>
??? begin(C& );
template <class C>
??? begin(C const& );
For lvalue containers, you get iterator, and for rvalue containers, you get const_iterator (or whatever the container-specific equivalent ends up being).
The one real problem in your code is returning decltype(auto). For lvalue containers, that's fine - you'll return a reference to an object whose lifetime exceeds the function. But for rvalue containers, that's returning a dangling reference. You'll want to return a reference for lvalue containers and a value for rvalue containers.
On top of that, forward-ing the containers into begin()/end() is probably not what you want to do. It'd be more efficient to conditionally wrap the result of the select() as a move iterator. Something like this answer of mine:
template <typename Container,
typename V = decltype(*std::begin(std::declval<Container&>())),
typename R = std::conditional_t<
std::is_lvalue_reference<Container>::value,
V,
std::remove_reference_t<V>
>
>
constexpr R operator()(Container&& c)
{
auto it = select(std::begin(c), std::end(c));
return *make_forward_iterator<Container>(it);
}
There's probably a less verbose way to express all of that.
You presumably realize that you wouldn't want to std::move an object being passed to multiple functions:
std::string s = "hello";
std::string hello1 = std::move(s);
std::string hello2 = std::move(s); // hello2 != "hello"
The role of forward is simply to restore any rvalue status that a parameter had when it was passed to the function.
We can quickly demonstrate that it is bad practice by forwarding one parameter two times to a function that has a move effect:
#include <iostream>
#include <string>
struct S {
std::string name_ = "defaulted";
S() = default;
S(const char* name) : name_(name) {}
S(S&& rhs) { std::swap(name_, rhs.name_); name_ += " moved"; }
};
void fn(S s)
{
std::cout << "fn(" << s.name_ << ")\n";
}
template<typename T>
void fwd_test(T&& t)
{
fn(std::forward<T>(t));
fn(std::forward<T>(t));
}
int main() {
fwd_test(S("source"));
}
http://ideone.com/NRM8Ph
If forwarding was safe, we should see fn(source moved) twice, but instead we see:
fn(source moved)
fn(defaulted moved)
In general, yes, this is potentially dangerous.
Forwarding a parameter ensures that if the value received by the universal reference parameter is an rvalue of some sort, it will continue to be an rvalue when it is forwarded. If the value is ultimately forwarded to a function (such as a move-constructor) that consumes the value by moving from it, its internal state is not likely to be valid for use in subsequent calls.
If you do not forward the parameter, it will not (in general) be eligible for move operations, so you would be safe from such behavior.
In your case, front and back (both the free functions and the member functions) do not perform a move on the container, so the specific example you gave should be safe. However, this also demonstrates that there's no reason to forward the container, since an rvalue won't be given different treatment from an lvalue--which is the only reason to preserve the distinction by forwarding the value in the first place.

Efficient direct initialization of a std::vector

I have a struct, say
struct A {
A(int n) : n(n) {}
int n;
};
and I want to initialize a std::vector with some elements. I can do this by using an initialization list, or by emplacing the new elements:
// 1st version: 3 ctors, 3 copy ctors, 3 dtors
std::vector<A> v1{1, 2, 3};
// 2nd version: 3 ctors
std::vector<A> v2;
v2.reserve(3);
v2.emplace_back(4);
v2.emplace_back(5);
v2.emplace_back(6);
As the comments show, the first version calls 3 constructors, 3 copy constructors, and 3 destructors. The version with emplace only uses 3 constructors.
Question: Obviously the second version is better, but the first version is more succinct. Can I have the best of both worlds? Can I do a direct initialization without the extra cost?
(Here's a longer version of the A struct that shows what's happening.)
Since A is convertible from int, you can use the range constructor of vector:
auto inits = {1, 2, 3};
std::vector<A> v1{std::begin(inits), std::end(inits)};
Or in a single declaration-statement (assuming you can rely on RVO):
auto v1 = [inits={1, 2, 3}] { return std::vector<A>{std::begin(inits), std::end(inits)}; }();
Expanding on #ecatmur's answer, I've developed a piece of code that allows a very general solution for any type of vector and for any constructor calls. The constructor parameters for each element of the vector are stored in a tuple (of & or && as appropriate) which are then perfect-forwarded when the element is built. Each element is constructed only once, essentially equivalent to emplace_back. This forwarding would even allow a vector of move-only types to be built such as unique_ptr<?>.
(Update, due to RVO it should simply construct them in place. Unfortunately, however, the element type does require at least a copy-constructor or move-constructor to be visible, even if they are actually skipped by the optimizer. This means you can build a vector of unique_ptr, but not of mutex.)
auto v2 = make_vector_efficiently<A>(
pack_for_later(1) // 1-arg constructor of A
,pack_for_later(2,"two") // 2-arg constructor of A
,pack_for_later(3) // 1-arg constructor of A
);
The above code will create a vector<A> with three elements. In my example, A has two constructors, one which takes int,string as parameters.
pack_for_later builds a tuple that stores its parameters as &/&& references. That is then converted into on object (of type UniquePointerThatConverts, that has the desired conversion operator, in this case operator A().
Within make_vector_efficiently, an initializer list of these converter objects is built and then vector is constructed with the begin() and
end() of the initializer_list. You might expect that these iterators would be required to have type T* in order to construct a vector<T>, but it is sufficient that the type the iterator points to can convert to T.
The constructor then uses placement new to (copy-)construct from the converted object. But, thanks for RVO, the copy won't happen and the converter will be effectively doing the equivalent of emplace_back for us.
Anyway, any feedback appreciated. Finally, it's trivial to extend this to other containers besides vector.
Full code on Coliru Should work on any C++11 compiler.
Some more detailed notes, and copies of the important functions:
pack_for_later simply builds a std::tuple. The standard make_tuple isn't good enough as it ignores references. Each element of the tuple built by pack_for_later is a reference (& or && as appropriate, depending on whether the original parameter was an lvalue or rvalue)
template<typename ...T>
std:: tuple<T&&...> pack_for_later(T&&... args) {
// this function is really just a more
// 'honest' make_tuple - i.e. without any decay
return std:: tuple<T&&...> (std::forward<T>(args)...);
}
Next, make_vector_efficiently is the function that brings is all together. It's first parameter is the 'Target' type, the type of the elements in the vector we wish to create. The collection of tuples is converted into our special converter type UniquePointerThatConverts<Target> and the vector is constructed as discussed above.
template<typename Target, typename ...PackOfTuples>
auto make_vector_efficiently(PackOfTuples&&... args)
-> std::vector<Target>
{
auto inits = { UniquePointerThatConverts<Target>(std::forward<PackOfTuples>(args))...};
return std::vector<Target> {std::begin(inits), std::end(inits)};
}
Because A can have multiple constructors, and we want to be able to use any and all of them, pack_for_later can return many different types (don't forget about lvalues and rvalues too). But we need a single type to build the init list from. Therefore, we define a suitable interface:
template<typename Target>
struct ConvInterface {
virtual Target convert_to_target_type() const = 0;
virtual ~ConvInterface() {}
};
Each tuple is therefore converted to an object that implements this interface by make_Conv_from_tuple. It actually returns a unique_ptr to such an object which is then stored in a UniquePointerThatConverts that has the actual conversion operator. It is this type that is stored in the init list which is used to initialize the vector.
template<typename Target>
struct UniquePointerThatConverts {
std:: unique_ptr<ConvInterface<Target>> p; // A pointer to an object
// that implements the desired interface, i.e.
// something that can convert to the desired
// type (Target).
template<typename Tuple>
UniquePointerThatConverts(Tuple&& p_)
: p ( make_Conv_from_tuple<Target>(std:: move(p_)) )
{
//cout << __PRETTY_FUNCTION__ << endl;
}
operator Target () const {
return p->convert_to_target_type();
}
};
And, of course, the actual conversion operator which constructs from the pack.
template<typename Target, typename ...T>
struct Conv : public ConvInterface<Target> {
std::tuple<T...> the_pack_of_constructor_args;
Conv(std::tuple<T...> &&t) : the_pack_of_constructor_args(std:: move(t)) {}
Target convert_to_target_type () const override {
using idx = typename make_my_index_sequence<sizeof...(T)> :: type;
return foo(idx{});
}
template<size_t ...i>
Target foo(my_index_sequence<i...>) const {
// This next line is the main line, constructs
// something of the Target type (see the return
// type here) by expanding the tuple.
return {
std:: forward
< typename std:: tuple_element < i , std::tuple<T...> > :: type >
(std:: get<i>(the_pack_of_constructor_args))
...
};
}
};

Is it safe to pass as argument a member of an object which is moving

#include <iostream>
#include <string>
#include <map>
struct A {
int n { 42 };
std::string s { "ciao" };
};
int main() {
A a;
std::map<std::string, A> m;
std::cout << "a.s: " << a.s << std::endl; // print: "a.s: ciao"
m.emplace(a.s, std::move(a)); // a.s is a member of a, moved in the same line
std::cout << "in map: " << m.count("ciao") << std::endl; // print: "in map: 1"
std::cout << "a.s: " << a.s << std::endl; // print: "a.s: " (as expected, it has been moved)
}
Is it safe to pass as an argument a member of a "moving" object? In this case, emplace seems to work: the map has the expected key.
Interesting. I think it's safe, for convoluted reasons. (For the record, I also consider it very bad style -- an explicit copy costs you nothing here, since it will be moved into the map.)
First of all, the actual function call is not a problem. std::move only casts a to an rvalue reference, and rvalue references are just references; a is not immediately moved. emplace_back forwards its parameters to a constructor of std::pair<std::string, A>, and this is where things get interesting.
So, which constructor of std::pair is used? It has rather many, but two are relevant:
pair(const T1& x, const T2& y);
template<class U, class V> pair(U&& x, U&&y);
(See 20.3.2 in the standard), where T1 and T2 are the template arguments of std::pair. As per 13.3, we end up in the latter with U == const T1& and V == T2, which makes intuitive sense (otherwise moving into a std::pair would be effectively impossible). This leaves us with a constructor of the form
pair(const T1& x, T2 &&y) : first(std::forward(x)), second(std::forward(y)) { }
as per 20.3.2 (6-8).
So, is this safe? Helpfully, std::pair is defined in some detail, including memory layout. In particular, it states that
T1 first;
T2 second;
come in this order, so first will be initialized before second. This means that in your particular case, the string will be copied before it is moved away, and you're safe.
However, if you were doing it the other way around:
m.emplace(std::move(A.s), A); // huh?
...then you'd get funny effects.
What happens when you call m.emplace(a.s, std::move(a)); is that you are passing an l-value reference to a.s and an r-value reference to a to the emplace function. Whether this is safe depends on the implementation of that function. If it first rips the guts out of the second argument and then tries to use the first argument, you'll likely have a problem. If it first uses the first argument and then rips the guts out of the second argument, no problem. Since this is a standard library function, you cannot rely on the implementation, so we cannot conclude that the code is safe.
To make it safe, you can make sure that a copy of the string is made before the contents of the string are moved out of a.
m.emplace(std::string(a.s), std::move(a));
Now you are passing an r-value reference to a temporary copy of a.s and an r-value reference to a to the emplace function. So, it's safe in this case, because std::map::emplace takes a set of universal references. If you would do the same with a function that takes it second argument by value, it's unsafe, because the move constructor could be called before the copy of a.s is made (since evaluation order of function arguments is unspecified). Knowing that, this code is probably too smart to be maintained.
So, the clearest code is something like:
auto key = a.s;
m.emplace(std::move(key), std::move(a));

Why use variadic arguments now when initializer lists are available?

I've been wondering what are the advantages of variadic arguments over initializer lists. Both offer the same ability - to pass indefinite number of arguments to a function.
What I personally think is initializer lists are a little more elegant. Syntax is less awkward.
Also, it appears that initializer lists have significantly better performance as the number of arguments grows.
So what am I missing, besides the possibility to use use variadic arguments in C as well?
If by variadic arguments you mean the ellipses (as in void foo(...)), then those are made more or less obsolete by variadic templates rather than by initializer lists - there still could be some use cases for the ellipses when working with SFINAE to implement (for instance) type traits, or for C compatibility, but I will talk about ordinary use cases here.
Variadic templates, in fact, allow different types for the argument pack (in fact, any type), while the values of an initializer lists must be convertible to the underlying type of the initalizer list (and narrowing conversions are not allowed):
#include <utility>
template<typename... Ts>
void foo(Ts...) { }
template<typename T>
void bar(std::initializer_list<T>) { }
int main()
{
foo("Hello World!", 3.14, 42); // OK
bar({"Hello World!", 3.14, 42}); // ERROR! Cannot deduce T
}
Because of this, initializer lists are less often used when type deduction is required, unless the type of the arguments is indeed meant to be homogenous. Variadic templates, on the other hand, provide a type-safe version of the ellipses variadic argument list.
Also, invoking a function that takes an initializer list requires enclosing the arguments in a pair of braces, which is not the case for a function taking a variadic argument pack.
Finally (well, there are other differences, but these are the ones more relevant to your question), values in an initializer lists are const objects. Per Paragraph 18.9/1 of the C++11 Standard:
An object of type initializer_list<E> provides access to an array of objects of type const E. [...] Copying an initializer list does
not copy the underlying elements. [...]
This means that although non-copyable types can be moved into an initializer lists, they cannot be moved out of it. This limitation may or may not meet a program's requirement, but generally makes initializer lists a limiting choice for holding non-copyable types.
More generally, anyway, when using an object as an element of an initializer list, we will either make a copy of it (if it is an lvalue) or move away from it (if it is an rvalue):
#include <utility>
#include <iostream>
struct X
{
X() { }
X(X const &x) { std::cout << "X(const&)" << std::endl; }
X(X&&) { std::cout << "X(X&&)" << std::endl; }
};
void foo(std::initializer_list<X> const& l) { }
int main()
{
X x, y, z, w;
foo({x, y, z, std::move(w)}); // Will print "X(X const&)" three times
// and "X(X&&)" once
}
In other words, initializer lists cannot be used to pass arguments by reference (*), let alone performing perfect forwarding:
template<typename... Ts>
void bar(Ts&&... args)
{
std::cout << "bar(Ts&&...)" << std::endl;
// Possibly do perfect forwarding here and pass the
// arguments to another function...
}
int main()
{
X x, y, z, w;
bar(x, y, z, std::move(w)); // Will only print "bar(Ts&&...)"
}
(*) It must be noted, however, that initializer lists (unlike all other containers of the C++ Standard Library) do have reference semantics, so although a copy/move of the elements is performed when inserting elements into an initializer list, copying the initializer list itself won't cause any copy/move of the contained objects (as mentioned in the paragraph of the Standard quoted above):
int main()
{
X x, y, z, w;
auto l1 = {x, y, z, std::move(w)}; // Will print "X(X const&)" three times
// and "X(X&&)" once
auto l2 = l1; // Will print nothing
}
Briefly, C-style variadic functions produce less code when compiled than C++-style variadic templates, so if you're concerned about binary size or instruction cache pressure, you should consider implementing your functionality with varargs instead of as a template.
However, variadic templates are significantly safer and produce far more usable error messages, so you'll often want to wrap your out-of-line variadic function with an inline variadic template, and have users call the template.