[英]C++: How can I pass keys and values into a constructor to make a map without copying the values of the map during construction?
Here is a minimal example where an object of type WrapMap
contains an unordered_map
.这是一个最小的示例,其中
WrapMap
类型的对象包含unordered_map
。 The only thing that will change in the map is the values, not the length and not the keys.映射中唯一会改变的是值,而不是长度和键。
However, I have found that each value passed into each pair is copied twice.但是,我发现传递给每对的每个值都被复制了两次。 By using
move
, it seems to have reduced the number of copies by 1 (although the move doesn't show up in the output, so maybe I've done something wrong).通过使用
move
,它似乎将副本数量减少了 1(尽管移动没有出现在输出中,所以也许我做错了什么)。
#include <iostream>
#include <unordered_map>
using std::cout;
struct MyStruct {
int x;
MyStruct(int x) : x(x) { cout << "Constructed " << this << " from " << x << "\n"; }
MyStruct(const MyStruct& from) : x(from.x) { cout << "Copied " << this << " from " << &from << "\n"; }
MyStruct(MyStruct&& from) : x(from.x) { cout << "Moved " << this << " from " << &from << "\n"; }
~MyStruct() { cout << "Destructed " << this << " from " << x << "\n"; }
};
struct WrapMap {
std::unordered_map<std::string, MyStruct>&& my_map;
WrapMap(std::unordered_map<std::string, MyStruct>&& kv)
: my_map(std::move(kv)) {
/*
// Just to make sure it inputs the values correctly
cout << "{";
for (auto it = my_map.begin(); it != my_map.end(); ++it) {
if (it != my_map.begin()) cout << ", ";
cout << it->first << ": MyStruct " << it->second.x;
}
cout << "}\n";
*/
}
};
int main() {
WrapMap object({
{"foo", 2},
// several pairs
});
}
Constructed 0x7ffd76fadbb8 from 2
Copied 0x2611c80 from 0x7ffd76fadbb8
{foo: MyStruct 2}
Destructed 0x7ffd76fadbb8 from 2
Destructed 0x2611c80 from 2
My assumption is that the long pointer points to const memory (just a guess) and so it has to copy each element from const memory to non-const memory.我的假设是长指针指向常量内存(只是一个猜测),因此它必须将每个元素从常量内存复制到非常量内存。
I have attempted to use an initializer_list<pair<string, MyStruct>>
but I couldn't convert it to an unordered_map
.我曾尝试使用
initializer_list<pair<string, MyStruct>>
但无法将其转换为unordered_map
。
std::unordered_map<std::string, MyStruct> object = { {"foo", 2} }
calls the copy constructor for each value, it seems. std::unordered_map<std::string, MyStruct> object = { {"foo", 2} }
似乎为每个值调用了复制构造函数。
How can I make it so that each key is never copied (or at least minimise it?)我如何才能使每个密钥永远不会被复制(或至少将其最小化?)
Related: Insert in unordered map calls constructor相关: 插入无序映射调用构造函数
You can use the emplace
member function of unordered_map
:您可以使用
unordered_map
的emplace
成员函数:
Inserts a new element into the container constructed in-place with the given args if there is no element with the key in the container.
如果容器中没有带有键的元素,则将一个新元素插入到使用给定参数就地构造的容器中。
Careful use of emplace allows the new element to be constructed while avoiding unnecessary copy or move operations.
小心使用 emplace 允许构造新元素,同时避免不必要的复制或移动操作。 The constructor of the new element (ie
std::pair<const Key, T>
) is called with exactly the same arguments as supplied to emplace, forwarded viastd::forward<Args>(args)...
.新元素的构造函数(即
std::pair<const Key, T>
)使用与提供给 emplace 的参数完全相同的参数调用,通过std::forward<Args>(args)...
转发。 [...][...]
std::unordered_map<std::string, MyStruct> m;
m.emplace(std::make_pair("foo", 2));
As of C++17, you can also make use of try_emplace
which allows retaining a given resource passed to it if the key already exists:从 C++17 开始,您还可以使用
try_emplace
,如果键已经存在,它允许保留传递给它的给定资源:
[...] Unlike
insert
oremplace
, these functions do not move from rvalue arguments if the insertion does not happen , which makes it easy to manipulate maps whose values are move-only types, such asstd::unordered_map<std::string, std::unique_ptr<foo>>
.[...] 与
insert
或emplace
不同,如果插入没有发生,这些函数不会从右值参数移动,这使得操作其值是仅移动类型的映射变得容易,例如std::unordered_map<std::string, std::unique_ptr<foo>>
。 In addition,try_emplace
treats the key and the arguments to the mapped_type separately, unlikeemplace,
which requires the arguments to construct avalue_type
(that is, astd::pair
) [...].此外,与 emplace 不同,
try_emplace
将键和参数分别处理为 maped_typeemplace,
后者需要参数来构造value_type
(即std::pair
)[...]。
std::unordered_map<std::string, MyStruct> m;
m.try_emplace("foo", 2);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.