考虑以下计划:
#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打印小写字母序列。
谁是对的?或者它只是标准中的一些环洞?
答案 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
具有未指定的值,但是根据上述子句,允许发生这种情况。所以要回答你的问题,这个程序没有正确的行为。