C++;标准保证插入关联容器失败不会修改右值引用参数? #包括 #包括 #包括 使用名称空间std::literals; int main() { auto coll=std::set{“hello”s}; auto s=“hello”s; coll.insert(std::move(s)); 断言(“hello”s==s);//总是正常吗? } < > > C++标准是否保证插入关联容器的失败不会修改rValor引用参数?< /强>
编号< /p> 虽然指出当且仅当没有等价键时才会插入元素,但这并不保证参数不会被修改 事实上,[map.modifiers]说C++;标准保证插入关联容器失败不会修改右值引用参数? #包括 #包括 #包括 使用名称空间std::literals; int main() { auto coll=std::set{“hello”s}; auto s=“hello”s; coll.insert(std::move(s)); 断言(“hello”s==s);//总是正常吗? } < > > C++标准是否保证插入关联容器的失败不会修改rValor引用参数?< /强> ,c++,stl,language-lawyer,rvalue-reference,pass-by-rvalue-reference,C++,Stl,Language Lawyer,Rvalue Reference,Pass By Rvalue Reference,编号< /p> 虽然指出当且仅当没有等价键时才会插入元素,但这并不保证参数不会被修改 事实上,[map.modifiers]说 #include <set> #include <string> #include <cassert> using namespace std::literals; int main() { auto coll = std::set{ "hello"s }; auto s = "hello"s; coll.
#include <set>
#include <string>
#include <cassert>
using namespace std::literals;
int main()
{
auto coll = std::set{ "hello"s };
auto s = "hello"s;
coll.insert(std::move(s));
assert("hello"s == s); // Always OK?
}
- (2个动作)
- (一步)
- 明确无误否。标准没有这种保证,这就是存在的原因
见附注:
与insert或emplace不同,这些函数不会从右值移动
如果插入未发生,则返回参数,这使得
操作值为仅移动类型的贴图,例如
std::map
。此外,try\u emplace
分别处理映射的_类型的键和参数,与
emplace
,它需要参数来构造一个值\u类型
是,一个std::pair
)
(仅适用于C++17)
我相信正确的答案介于纳萨诺利弗(现已删除)的答案和安迪格的答案之间
正如AndyG指出的那样,这样的保证在一般情况下是不可能存在的:有时候,库实际上必须执行移动构造,以确定插入是否可以发生。emplace
功能就是这种情况,其行为由标准规定为:
效果:插入由std::forward(args).
构造的value\u type
对象t
,当且仅当容器中没有与t
的键等效的元素时
我们可以将其解释为,不管发生什么情况,都要构造对象t
,如果插入无法发生,则将其丢弃,因为值t
或t.first
分别已存在于集合或映射中。由于std::map
的模板对插入(P&&)
方法是根据emplace
指定的,正如AndyG所指出的,它具有相同的行为。正如SergeyA指出的那样,try\u emplace
方法旨在避免这个问题
但是,在OP给出的特定示例中,插入的值的类型与容器的值类型完全相同。NathanOliver之前给出的一般要求段落规定了此类插入调用的行为:
效果:插入t
当且仅当容器中没有键等于t
键的元素时
在这种情况下,在没有插入的情况下,没有为库提供修改参数的许可。我相信,除了标准明确允许的之外,调用库函数不应该有任何明显的副作用。因此,这种情况下,t
不能修改。@user877329std::set
没有try\u emplace
,因此类型转换(或缺少类型转换)的情况不适用于它。在无序映射
和映射
中,try\u emplace
的键
参数由常量引用接收,因此无法从中移动。这两种情况下的值都是通过完美转发接收的,因此只有通过右值引用接收时才有资格从中移动,这意味着try\u emplace
无法修改参数,除非您允许。
template <class P>
pair<iterator, bool> insert(P&& x);
#include <iostream>
#include <utility>
#include <string>
#include <map>
struct my_class
{
my_class() = default;
my_class(my_class&& other)
{
std::cout << "move constructing my_class\n";
val = other.val;
}
my_class(const my_class& other)
{
std::cout << "copy constructing my_class\n";
val = other.val;
}
my_class& operator=(const my_class& other)
{
std::cout << "copy assigning my_class\n";
val = other.val;
return *this;
}
my_class& operator=(my_class& other)
{
std::cout << "move assigning my_class\n";
val = other.val;
return *this;
}
bool operator<(const my_class& other) const
{
return val < other.val;
}
int val = 0;
};
int main()
{
std::map<my_class, int> my_map;
my_class a;
my_map[a] = 1;
std::pair<my_class, int> b = std::make_pair(my_class{}, 2);
my_map.insert(std::move(b)); // will print that the move ctor was called
}