【发布时间】:2014-09-10 13:27:35
【问题描述】:
有没有办法设置std::pair?
std::unordered_map<int, std::pair<std::string, std::string>> my_map;
my_map.emplace(1, "foo", "bar"); // Error
当然可以插入:
my_map[2] = std::make_pair("bar", "foo");
但这不需要不必要的复制/移动吗?
【问题讨论】:
有没有办法设置std::pair?
std::unordered_map<int, std::pair<std::string, std::string>> my_map;
my_map.emplace(1, "foo", "bar"); // Error
当然可以插入:
my_map[2] = std::make_pair("bar", "foo");
但这不需要不必要的复制/移动吗?
【问题讨论】:
有没有办法放置一个 std::pair?
参数需要适合pair<int, pair<string,string>>的构造函数,映射的value_type:
my_map.emplace(1, std::make_pair("foo", "bar"));
但这不需要不必要的复制/移动吗?
没有; make_pair 生成一对指向字符串文字的指针,然后用于初始化(在emplace 的情况下)或分配给(在[] 的情况下)映射中包含的字符串。
【讨论】:
emplace 不会创建对象然后将其移动到容器中;它使用 forwarding 将参数转发给容器,然后一旦容器确定了它希望在内存中构造对象的位置,容器就会调用对象构造函数。 (误导性的函数名称!)
在这种情况下,放置“值类型”std::pair 的部分意义不大,因为std::string 既可以有效地从 C 字符串转换,也可以有效地移动到地图中。简单的m.emplace( 3, std::make_pair( "bob", "alice" ) ),您就可以达到最佳效率的 99%。
但是,如果您有一个映射到无法以这种方式有效构造的类型的 std::map,则 C++11 会为 std::pair 提供 std::piecewise_construct 为 emplaced。
struct A { }; // nothing
struct C { C(C&&)=delete; }; // no copy/move
struct B { B()=delete; B(B&&)=delete; B(C&&, C&&) {}; }; // no copy/move, only annoying ctor
std::map< int, std::pair<A,B> > test;
// test.emplace( 0, std::make_pair( A{}, B{} ); // does not compile
// test.emplace( 0, std::make_pair( A{}, B{C{},C{}} ); // does not compile
test.emplace( std::piecewise_construct,
std::make_tuple(0),
std::forward_as_tuple(
std::piecewise_construct,
std::forward_as_tuple(A{}),
std::forward_as_tuple( C{}, C{} )
)
); // compiles!
这是一个极端的极端情况,因为高效移动的对象更为常见。
【讨论】:
std::piecewise_construct 是 C++11,而不是 C++14。
是的,有:
my_map.emplace(1, std::make_pair("foo", "bar"));
【讨论】:
对于 C++17,您可以使用 try_emplace:
std::unordered_map<int, std::pair<std::string, std::string>> my_map;
my_map.try_emplace(1, "foo", "bar");
【讨论】: