在存在虚拟基础的情况下移动语义

时间:2015-05-12 14:48:57

标签: c++11 move-semantics virtual-inheritance diamond-problem

考虑以下计划:

#include <iostream>
#include <ostream>
#include <string>
#include <utility>

using namespace std;

struct Name { string s; Name(string s) : s(move(s)) { } };

struct A : virtual Name { A(string s) : Name(move(s)) { } };

struct B : virtual Name { B(string s) : Name(move(s)) { } };

struct C : A, B { C(string s) : A(string()), B(string()), Name(move(s)) { } };

C f() { return C("abcdefghijklmnopqrstuvwxyz"); }

int main()
{
    C c1("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
    C c2("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
    C ff = f();
    c1 = f();
    c2 = ff;
    cout << "C1 = " << c1.s << " " << "C2 = " << c2.s << "\n";
    return 0;
}

gcc(4.9.2)(http://ideone.com/G7uzCQ)和clang ++都为C1和C2打印不同的值,而Visual Studio 2013和2015则始终为C1和C2打印小写字母序列。

谁是对的?或者它只是标准中的一些环洞?

1 个答案:

答案 0 :(得分:3)

来自§12.8/ 28 [class.copy]:

  

未指定表示虚拟基类的子对象是否被多次分配   隐式定义的复制/移动赋值运算符。 [例如:

struct V { };
struct A : virtual V { };
struct B : virtual V { };
struct C : B, A { };
     

未指定虚拟基类子对象V是否由C的隐式定义的复制/移动赋值运算符赋值。 - 结束例子]

根据标准,未指定程序的行为。 Visual Studio决定调用赋值运算符一次,而GCC和Clang执行两次。移动操作的结果使移动对象处于有效但未指定的状态,因此随后再次从临时移动将使s具有未指定的值,但是根据上述子句,允许发生这种情况。所以要回答你的问题,这个程序没有正确的行为。