在存在虚拟基础的情况下移动语义
Move semantics in the presence of virtual bases
考虑以下程序:
#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 打印小写字母序列。
谁是对的?或者它只是标准中的一些漏洞?
来自 §12.8/28 [class.copy]:
It is unspecified whether subobjects representing virtual base classes are assigned more than once by the
implicitly-defined copy/move assignment operator. [ Example:
struct V { };
struct A : virtual V { };
struct B : virtual V { };
struct C : B, A { };
It is unspecified whether the virtual base class subobject V
is assigned twice by the implicitly-defined copy-/move assignment operator for C
. — end example ]
根据标准,您的程序的行为未指定。 Visual Studio 决定调用赋值运算符一次,而 GCC 和 Clang 调用两次。移动操作的结果使移出对象处于有效但未指定的状态,因此随后再次从临时对象移动将留下 s
具有未指定的值,但根据上述条款,这是允许发生的。所以要回答你的问题,这个程序没有正确的行为。
考虑以下程序:
#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 打印小写字母序列。
谁是对的?或者它只是标准中的一些漏洞?
来自 §12.8/28 [class.copy]:
It is unspecified whether subobjects representing virtual base classes are assigned more than once by the implicitly-defined copy/move assignment operator. [ Example:
struct V { }; struct A : virtual V { }; struct B : virtual V { }; struct C : B, A { };
It is unspecified whether the virtual base class subobject
V
is assigned twice by the implicitly-defined copy-/move assignment operator forC
. — end example ]
根据标准,您的程序的行为未指定。 Visual Studio 决定调用赋值运算符一次,而 GCC 和 Clang 调用两次。移动操作的结果使移出对象处于有效但未指定的状态,因此随后再次从临时对象移动将留下 s
具有未指定的值,但根据上述条款,这是允许发生的。所以要回答你的问题,这个程序没有正确的行为。