由于C++17 std::map
提供了两种新的插入方法:insert_or_assign()
和try_emplace()
,正如sp2danny 的评论中所提到的那样。
insert_or_assign()
基本上,insert_or_assign()
是operator[]
. 与 相比operator[]
,insert_or_assign()
不要求地图的值类型是默认可构造的。例如,以下代码无法编译,因为MyClass
没有默认构造函数:
class MyClass {
public:
MyClass(int i) : m_i(i) {};
int m_i;
};
int main() {
std::map<int, MyClass> myMap;
// VS2017: "C2512: 'MyClass::MyClass' : no appropriate default constructor available"
// Coliru: "error: no matching function for call to 'MyClass::MyClass()"
myMap[0] = MyClass(1);
return 0;
}
但是,如果您替换myMap[0] = MyClass(1);
为以下行,则代码编译并按预期进行插入:
myMap.insert_or_assign(0, MyClass(1));
此外,与 类似insert()
,insert_or_assign()
返回 a pair<iterator, bool>
。布尔值是true
是否发生了插入以及false
是否完成了分配。迭代器指向被插入或更新的元素。
try_emplace()
与上述类似,try_emplace()
是对emplace()
. 相反emplace()
,如果由于映射中已经存在的键而导致插入失败,try_emplace()
则不会修改其参数。例如,以下代码尝试使用已存储在地图中的键来放置元素(请参阅 *):
int main() {
std::map<int, std::unique_ptr<MyClass>> myMap2;
myMap2.emplace(0, std::make_unique<MyClass>(1));
auto pMyObj = std::make_unique<MyClass>(2);
auto [it, b] = myMap2.emplace(0, std::move(pMyObj)); // *
if (!b)
std::cout << "pMyObj was not inserted" << std::endl;
if (pMyObj == nullptr)
std::cout << "pMyObj was modified anyway" << std::endl;
else
std::cout << "pMyObj.m_i = " << pMyObj->m_i << std::endl;
return 0;
}
输出(至少对于 VS2017 和 Coliru):
pMyObj 没有被插入
pMyObj 还是被修改了
如您所见,pMyObj
不再指向原始对象。但是,如果您替换auto [it, b] = myMap2.emplace(0, std::move(pMyObj));
为以下代码,则输出看起来会有所不同,因为pMyObj
保持不变:
auto [it, b] = myMap2.try_emplace(0, std::move(pMyObj));
输出:
pMyObj 未插入
pMyObj pMyObj.m_i = 2
Coliru 上的代码
请注意:我试图让我的解释尽可能简短和简单,以使它们适合这个答案。要获得更准确和全面的描述,我建议阅读Fluent C++上的这篇文章。