使用std :: move的未定义行为

时间:2015-09-02 06:36:33

标签: c++ c++11

来自cppreference的move page

  

除非另有说明,否则所有标准库对象都有   已被移动的位置处于有效但未指定的状态。那是,   只有没有先决条件的函数,例如赋值   操作符,可以在从

移出后在对象上安全使用

因此,从同一页面上的示例中,下面的代码被视为未定义的行为

vector<string> v_string;
string example = "example";
v_string.push_back(move(example));
cout << example << endl;

MSVC将在控制台上不输出任何内容,但如果我这样做

vector<int> v_int;
int number = 10;
v_int.push_back(move(number));
cout << number << endl;

将输出10.这是否有原因?或者它总是未定义的行为?

3 个答案:

答案 0 :(得分:10)

未指定并不代表未定义。

根据C ++ 11标准,第17.3.26节:

  

有效但未指定的状态   除了满足对象的不变量并且对象上的操作按其类型指定的行为

之外,未指定的对象状态

当对象处于有效状态时,您可以将其流式传输到输出,因为流没有其他前提条件。然而打印的是未指定的,所以它可能只打印任何东西,或打印出你父亲闻到的接骨木果。您不能安全地做的是使用具有附加前提条件的函数,例如back(),此外还需要字符串非空。有效字符串可以为空。

对于未指定但有效的状态,包含旧值是完全可接受的选项。对于int等基本类型,简单副本只是执行移动的最有效方式。

还应该注意int 不是标准库对象,而是基本类型(如3.9.1节所定义)。因此,您的报价不适用。

答案 1 :(得分:3)

这是因为string可以通过窃取指向实际字符的指针来有效move d,这就是编译器所做的事情,从{move d离开1}}&#34;空&#34;。 string无法有效int d,您只需复制一份。因此旧的move仍在那里。但这是没有记录的。只是不要使用int编辑过的对象,不要依赖于未指定的行为。

答案 2 :(得分:0)

未定义的行为仅仅意味着

  

本国际标准没有要求的行为。   允许的未定义行为包括忽略这种情况   完全具有不可预测的结果,在翻译过程中表现出色   或者以文件化的方式执行程序   环境(有或没有发出诊断信息),到   终止翻译或执行(发布a   诊断信息)。许多错误的程序结构不会产生   未定义的行为;他们需要被诊断出来。

如果您有兴趣,请查看"What every C programmer should know about undefined behavior"。这真是令人大开眼界。

在您的情况下,它不是未定义的行为,而是未指定的状态: 在21.4.2.16中,C ++标准定义了移动构造函数的语义:

  

构造一个basic_string类的对象,如表69所示。   存储的分配器由alloc构造。在第二种形式中,str保持在具有未指定值的有效状态。

&#34;第二种形式&#34;是移动构造函数,因此字符串处于未指定状态。

这意味着对象必须处于满足不变量的状态,但未指定任何其他内容。对于字符串,任何内容都可以。