简体   繁体   English

C++:如何将键和值传递给构造函数以制作地图而不在构造过程中复制地图的值?

[英]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相关: 插入无序映射调用构造函数

emplace进驻

You can use the emplace member function of unordered_map :您可以使用unordered_mapemplace成员函数:

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 via std::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));

C++17: try_emplace C++17:try_emplace

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 or emplace , 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 as std::unordered_map<std::string, std::unique_ptr<foo>> . [...] 与insertemplace不同,如果插入没有发生,这些函数不会从右值参数移动,这使得操作其值是仅移动类型的映射变得容易,例如std::unordered_map<std::string, std::unique_ptr<foo>> In addition, try_emplace treats the key and the arguments to the mapped_type separately, unlike emplace, which requires the arguments to construct a value_type (that is, a std::pair ) [...].此外,与 emplace 不同, try_emplace将键和参数分别处理为 maped_type emplace,后者需要参数来构造value_type (即std::pair )[...]。

std::unordered_map<std::string, MyStruct> m;
m.try_emplace("foo", 2);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM