How can I emplace an empty vector into a std::map? For example, if I have a std::map<int, std::vector<int>>, and I want map[4] to contain an empty std::vector<int>, what can I call?
If you use operator[](const Key&), the map will automatically emplace a value-initialized (i.e. in the case of std::vector, default-constructed) value if you access an element that does not exist. See here:
http://en.cppreference.com/w/cpp/container/map/operator_at
(Since C++ 11 the details are a tad more complicated, but in your case this is what matters).
That means if your map is empty and you do map[4], it will readily give you a reference to an empty (default-constructed) vector. Assigning an empty vector is unnecessary, although it may make your intent more clear.
Demo: https://godbolt.org/g/rnfW7g
Unfortunately the strictly-correct answer is indeed to use std::piecewise_construct as the first argument, followed by two tuples. The first represents the arguments to create the key (4), and the second represents the arguments to create the vector (empty argument set).
It would look like this:
map.emplace(std::piecewise_construct, // signal piecewise construction
std::make_tuple(4), // key constructed from int(4)
std::make_tuple()); // value is default constructed
Of course this looks unsightly, and other alternatives will work. They may even generate no more code in an optimised build:
This one notionally invokes default-construction and move-assignment, but it is likely that the optimiser will see through it.
map.emplace(4, std::vector<int>());
This one invokes default-construction followed by copy-assignment. But again, the optimiser may well see through it.
map[4] = {};
To ensure an empty vector is placed at position 4, you may simply attempt to clear the vector at position 4.
std::map<int, std::vector<int>> my_map;
my_map[4].clear();
As others have mentioned, the indexing operator for std::map will construct an empty value at the specified index if none already exists. If that is the case, calling clear is redundant. However, if a std::vector<int> does already exist, the call to clear serves to, well, clear the vector there, resulting in an empty vector.
This may be more efficient than my previous approach of assigning to {} (see below), because we probably plan on adding elements to the vector at position 4, and we don't pay any cost of new allocation this way. Additionally, if previous usage of my_map[4] indicates future usage, then our new vector will likely be eventually resized to the nearly the same size as before, meaning we save on reallocation costs.
Previous approach:
just assign to {} and the container should properly construct an empty vector there:
std::map<int, std::vector<int>> my_map;
my_map[4] = {};
std::cout << my_map.size() << std::endl; // prints 1
Demo
Edit: As Jodocus mentions, if you know that the std::map doesn't already contain a vector at position 4, then simply attempting to access the vector at that position will default-construct one, e.g.:
std::map<int, std::vector<int>> my_map;
my_map[4]; // default-constructs a vector there
What's wrong with the simplest possible solution? std::map[4] = {};.
In modern C++, this should do what you want with no or at least, very little, overhead.
If you must use emplace, the best solution I can come up with is this:
std::map<int, std::vector<int>> map;
map.emplace(4, std::vector<int>());
Use piecewise_construct with std::make_tuple:
map.emplace(std::piecewise_construct, std::make_tuple(4), std::make_tuple());
We are inserting an empty vector at position 4.
And if there is a general case like, emplacing a vector of size 100 with 10 filled up then:
map.emplace(std::piecewise_construct, std::make_tuple(4), std::make_tuple(100, 10));
piecewise_construct: This constant value is passed as the first argument to construct a pair object to select the constructor form that constructs its members in place by forwarding the elements of two tuple objects to their respective constructor.
Related
I am trying to understand and make sure if three different ways to insert elements into a std::map are effectively the same.
std::map<int, char> mymap;
Just after declaring mymap - will inserting an element with value a for key 10 be same by these three methods?
mymap[10]='a';
mymap.insert(mymap.end(), std::make_pair(10, 'a'));
mymap.insert(std::make_pair(10, 'a'));
Especially, does it make any sense using mymap.end() when there is no existing element in std::map?
The main difference is that (1) first default-constructs a key object in the map in order to be able to return a reference to this object. This enables you to assign something to it.
Keep that in mind if you are working with types that are stored in a map, but have no default constructor. Example:
struct A {
explicit A(int) {};
};
std::map<int, A> m;
m[10] = A(42); // Error! A has no default ctor
m.insert(std::make_pair(10, A(42))); // Ok
m.insert(m.end(), std::make_pair(10, A(42))); // Ok
The other notable difference is that (as #PeteBecker pointed out in the comments) (1) overwrites existing entries in the map, while (2) and (3) don't.
Yes, they are effectively the same. Just after declaring mymap, all three methods turn mymap into {10, 'a'}.
It is OK to use mymap.end() when there is no existing element in std::map. In this case, begin() == end(), which is the universal way of denoting an empty container.
(1) is different from (2) and (3) if there exists an element with the same key. (1) will replace the element, where (2) and (3) will fail and return value denoting insertion didn't happen.
(1) also requires that mapped type is default constructible. In fact (1) first default constructs the object if not present already and replaces that with the value specified.
(2) and (3) are also different. To understand the difference we need to understand what the iterator in (2) does. From cppreference, the iterator refers to a hint where insertion happens as close to that hint as possible. There is a performance difference depending on the validity of the hint. Quoting from the same page:
Amortized constant if the insertion happens in the position just after the hint, logarithmic in the size of the container otherwise.(until C++11)
Amortized constant if the insertion happens in the position just before the hint, logarithmic in the size of the container otherwise. (since C++11)
So for large maps we can get a performance boost if we already know the position somehow.
Having said all of these, if the map is just created and you are doing the operation with no prior elements in the map as you said in the question then I would say that all three will be practically same (though there internal operation will be different as specified above).
I have a map of vectors:
std::map<int, std::vector<bool>> mymap
At times, I need to insert a new element:
auto& newvec = mymap[42];
// Add stuff to newvec
As far is I understand (and assuming that 42 is not yet in the map), this will give me newvec with length 0 (constructed as std::vector<bool> {}) which I can then extend.
Is there a way to initialize the vector to some size n right away?
(I am not concerned about performance, just wondering if there is a way to do this).
Wrapping the std::vector<bool>
You could wrap the std::vector<bool> you want to initialise in the following way:
template<size_t N>
struct myvector {
myvector(): data(N) {}
std::vector<bool> data;
};
Then, declare mymap as a map whose value type is of this wrapper type, myvector<N>, instead of std::vector<bool>. For example, for N equal to 100:
std::map<int, myvector<100>> mymap;
If the key 42 does not exist in the map yet, then:
auto& newvec = mymap[42];
will create an instance of type myvector<100>, which in turns, initialises an std::vector<bool> of size 100.
You could access the created std::vector<bool> object either through myvector's data data member or by performing reinterpret_cast<std::vector<bool>&>(newvec).
Using std::map::find() and std::map::emplace()
Another approach would be to use std::map::find() instead of std::map::operator[]() to first find out whether a given key already exists in the map by comparing its returned iterator against the one returned by std::map::end(). If the given key does not exist, then construct the vector using std::map::emplace().
In your example, the newvec could be initialized for this approach by means of the ternary opererator:
auto it = mymap.find(42); // search for an element with the key 42
bool is_key_in_map = it != mymap.end();
// if the element with the given key exists, then return it, otherwise
// construct it
auto& newvec = is_key_in_map? it->second:
mymap.emplace(42, std::vector<bool>(100, true)).first->second;
Actually, you can directly call std::map::emplace() without checking whether the given key already exists, but that will cost the useless creation of a temporary object (i.e., the std::vector<bool> object) if the key is already present in the map:
auto& newvec = mymap.emplace(42, std::vector<bool>(100, true)).first->second;
Since C++17: std::map::try_emplace()
You could use std::map::try_emplace() instead of std::map::emplace():
auto& newvec = mymap.try_emplace(42, 100, true).first->second;
This way, the temporary object, std::vector<bool>(100, true), won't be constructed if the map already contains the given key (i.e., if it already contains the key 42). This is, therefore, more efficient than using std::map::emplace(), since no temporary object will be constructed if not necessary. However, it does require C++17.
Use map::try_emplace() (or map::emplace() before C++17)
std::vector has a constructor which takes an initial size and an initial uniform value. In your case, suppose you want 125 as the initial size. With a stand-alone vector, you would use:
size_t num_bools_we_want = 1234;
std::vector<bool> my_vec(num_bools_we_want, false);
Now, std::map has a method named map::try_emplace() which forwards arguments to a constructor of the value type, which effectively allows you to choose the constructor it will use for a new element. Here's how to use it
mymap.try_emplace(42, num_bools_we_want, false);
to create a value of std::vector<bool>(num_bools_we_want, false) for the key 42. No temporary vectors are created (regardless of compiler optimizations).
The only "problem" with this solution is that try_emplace() only exists since C++17. Since you asked about C++11 - that version of the standard introduced map::emplace(), which does almost the same thing except for an issue with making a copy of the key. See this question for a discussion of the difference between emplace() and try_emplace().
You can use map::emplace member function:
mymap.emplace(42, std::vector<bool>(125, false));
to create a value of std::vector<bool>(125, false) for the key 42.
As ネロク mentions, the above emplace call will construct the value std::vector<bool>(125, false) even if the key 42 already exists in the map (this is also documented in the cppreference page I linked above). If this is to be avoided, you can first check if the value already exists using map::find and insert the value only if the key doesn't exist. That is:
if (mymap.find(42) == mymap.end()) {
mymap.emplace(42, std::vector<bool>(125, false));
}
Both map::find and map::emplace has logarithmic time complexity; hence, calling find before emplace should not hurt the performance too much in performance critical scenarios.
Let's say I have a map<int, int>:
std::map<int, int> map;
map.emplace(1, 2);
map.insert({3, 4});
Will there be any difference between the two calls?
In the first call, the two integers will be copied by value to the emplace function and then again to the std::pair<int, int> constructor. In the second call, the two integers will be copied by value to the std::pair<int, int> constructor and then be copied by value to the internal std::pair<int, int> again as members of the first pair.
I understand the benefits of emplace for types like std::string where they would be copied by value in the second call and moved all the way in the first one, but is there any benefit in using emplace in the situation described?
Emplace is slower, if there is a chance that the emplace will fail (the key is already present).
This is because emplace is required to allocate a node and construct the pair<Key const, Value> into it, then extract the key from that node and check whether the key is already present, then deallocate the node if the key is already present. On the other hand insert can extract the key from the passed value to be inserted, so does not need to allocate a node if the insert would fail. See: performance of emplace is worse than check followed by emplace.
To fix this, C++17 adds a member function try_emplace(const key_type& k, Args&&... args) (etc.)
In case of success, there is no real difference between the two cases; the order of operations is different, but that will not affect performance in any predictable fashion. Code size will still be slightly larger for the emplace variant, as it has to be ready to perform more work in the failure case.
There are two ways (that I know) of assigning one vector to another:
std::vector<std:string> vectorOne, vectorTwo;
// fill vectorOne with strings
// First assign method
vectorTwo = vectorOne;
// Second assign method
vectorTwo.assign( vectorOne.begin(), vectorOne.end() );
Is there really difference within those methods or they are equal in terms of efficiency and safety when performed on very big vectors?
They're pretty much equivalent. The reason for the second is
that you might have types which need (implicit) conversion:
std::vector<int> vi;
std::vector<double> vd;
// ...
vd.assign( vi.begin(), vi.end() );
Or the type of the container might be different:
vd.assign( std::istream_iterator<double>( file ),
std::istream_iterator<double>() );
If you know that both of the containers are the same type, just
use assignment. It has the advantage of only using a single
reference to the source, and possibly allowing move semantics in
C++11.
The second form is generic, it works with any iterator types, and just copies the elements from the source vector.
The first form only works with exactly the same type of vector, it copies the elements and in C++11 might also replace the allocator by copying the allocator from the source vector.
In your example the types are identical, and use std::allocator which is stateless, so there is no difference. You should use the first form because it's simpler and easier to read.
They are equivalent in this case. [and C++03 standaerd]. The difference will be however if vectorTwo contains elements before assignment. Then
vectorTwo = vectorOne; // use operator=
// Any elements held in the container before the call
// are either assigned to or destroyed.
vectorTwo.assign() // any elements held in the container
// before the call are destroyed and replaced by newly
// constructed elements (no assignments of elements take place).
assign is needed because operator= takes single right-hand operand so assign is used when there is a need for a default argument value or range of values. What assign does could be done indirectly by first creating suitable vector and then assigning that:
void f(vector<Book>& v, list<Book>& l){
vector<Book> vt = (l.begin(), l.end());
v = vt;
}
however this can be both ugly and inefficient (example has been taken from Bjarne Stroustrup "The C++...")
Also note that if vector is not of the same type then there is also need for assign which allows implicit conversion:
vector<int> vi;
vector<double> vd;
// ...
vd.assign( vi.begin(), vi.end() );
I have an std::unordered_map, and I want both to increment the first value in a std::pair, hashed by key, and to create a reference to key. For example:
std::unordered_map<int, std::pair<int, int> > hash;
hash[key].first++;
auto it(hash.find(key));
int& my_ref(it->first);
I could, instead of using the [] operator, insert the data with insert(), but I'd allocate a pair, even if it were to be deallocated later, as hash may already have key -- not sure of it, though. Making it clearer:
// If "key" is already inserted, the pair(s) will be allocated
// and then deallocated, right?
auto it(hash.insert(std::make_pair(key, std::make_pair(0, 0))));
it->second.first++;
// Here I can have my reference, with extra memory operations,
// but without an extra search in `hash`
int& my_ref(it->first);
I'm pretty much inclined to use the first option, but I can't seem to decide which one is the best. Any better solution to this?
P.S.: an ideal solution for me would be something like an insertion that does not require an initial, possibly useless, allocation of the value.
As others have pointed out, a "allocating" a std::pair<int,int> is really nothing more than copying two integers (on the stack). For the map<int,pair<int,int>>::value_type, which is pair<int const, pair<int, int>> you are at three ints, so there is no significant overhead in using your second approach. You can slightly optimize by using emplace instead of insert i.e.:
// Here an `int` and a struct containing two `int`s are passed as arguments (by value)
auto it(hash.emplace(key, std::make_pair(0, 0)).first);
it->second.first++;
// You get your reference, without an extra search in `hash`
// Not sure what "extra memory operations" you worry about
int const& my_ref(it->first);
Your first approach, using both hash[key] and hash.find(key) is bound to be more expensive, because an element search will certainly be more expensive than an iterator dereference.
Premature copying of arguments on their way to construction of the unordered_map<...>::value_type is a negligible problem, when all arguments are just ints. But if instead you have a heavyweight key_type or a pair of heavyweight types as mapped_type, you can use the following variant of the above to forward everything by reference as far as possible (and use move semantics for rvalues):
// Here key and arguments to construct mapped_type
// are forwarded as tuples of universal references
// There is no copying of key or value nor construction of a pair
// unless a new map element is needed.
auto it(hash.emplace(std::piecewise_construct,
std::forward_as_tuple(key), // one-element tuple
std::forward_as_tuple(0, 0) // args to construct mapped_type
).first);
it->second.first++;
// As in all solutions, get your reference from the iterator we already have
int const& my_ref(it->first);
How about this:
auto it = hash.find(key);
if (it == hash.end()) { it = hash.emplace(key, std::make_pair(0, 0)).first; }
++it->second.first;
int const & my_ref = it->first; // must be const
(If it were an ordered map, you'd use lower_bound and hinted insertion to recycle the tree walk.)
If I understand correctly, what you want is an operator[] that returns an iterator, not a mapped_type. The current interface of unordered_map does not provide such feature, and operator[] implementation relies on private members (at least the boost implementation, I don't have access C++11 std files in my environment).
I suppose that JoergB's answer will be faster and Kerrek SB's one will have a smaller memory footprint. It's up to you to decide what is more critical for your project.