简体   繁体   中英

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 . 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).

#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 .

std::unordered_map<std::string, MyStruct> object = { {"foo", 2} } calls the copy constructor for each value, it seems.

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 :

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. 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::unordered_map<std::string, MyStruct> m;
m.emplace(std::make_pair("foo", 2));

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:

[...] 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>> . 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 ) [...].

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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