I have got std::vector<std::map<int, std::unique_ptr<int>>>
container (if to simplify). Initially, I have to insert in std::vector
some amount of std::map
, each of them will have one key-value pair. I tried such code:
#include <iostream>
#include <map>
#include <vector>
#include <memory>
using namespace std;
int main()
{
vector<map<int, std::unique_ptr<int>>> data{};
for (int x = 0; x < 10; x++)
{
data.emplace_back(std::make_pair(x, std::make_unique<int>(x)));
}
}
But it did not work. How can I change it to make it work as expected?
EDIT: I understood my mistake, I had to use this piece of code to add th element:
std::map<int, std::unique_ptr<int>> m;
m.emplace(x, std::make_unique<int>(y));
data.emplace_back(std::move(m));
Then, the code will work in online compilers, but it still does not work in Visual Studio.
The cause of your error is that emplace_back
will attempt to construct a map
in the vector
like:
std::map<int, std::unique_ptr<int>>(std::make_pair(...))
See also: std::map
constructors
However, this is not possible, because the constructor which takes pairs is taking std::initializer_list<std::pair<K, V>>
. There is no constructor that takes a single pair. The correct way is:
map<int, unique_ptr>{std::make_pair(...)}
However, constructors taking std::initializer_list<T>
require T
to be copyable, and std::unique_ptr<int>
is not copyable, so the containing T = std::pair<int, std::unique_ptr<int>>
also isn't copyable. This leaves us with the following solution:
#include <iostream>
#include <map>
#include <vector>
#include <memory>
int main()
{
using map_type = std::map<int, std::unique_ptr<int>>;
std::vector<map_type> data{};
for (int x = 0; x < 10; x++)
{
for (int y = 0; y < 10; y++)
{
map_type m;
m.emplace(x, std::make_unique<int>(y));
data.emplace_back(std::move(m));
}
}
}
See live example
In MSVC's standard library, it is impossible to use a std::vector<std::map<int, std::unique_ptr<int>>
. The reason is that due to strong exception guarantees, std::vector
requires its element type to be std::nothrow_move_constructible
, or copyable.
You can see that in the MSVC STL, std::map
has non-noexcept
move constructor:
map(map&& _Right) : _Mybase(_STD move(_Right)) {}
Here is a quick and dirty fix for this issue:
template <typename K, typename V>
struct nothrow_map : std::map<K, V> {
nothrow_map() = default;
nothrow_map(nothrow_map&& other) noexcept : std::map<K, V>(std::move(other)) {}
};
// ...
using map_type = nothrow_map<int, std::unique_ptr<int>>;
See also: std::move_if_noexcept
(used by std::vector
internally)