有一个限制:
同样,在对象的生命周期开始之前但在之后 对象占用的存储空间已被分配,或之后 对象的生命周期已经结束,在存储之前就已经存在了 对象占用被重用或释放,任何 glvalue引用 原始对象可能会被使用,但只能以有限的方式使用。对于一个对象 正在建设或破坏,见12.7。否则,这样的glvalue 指分配存储(3.7.4.2),并使用的属性 不依赖于其值的glvalue是明确定义的。该程序 在以下情况下具有未定义的行为:
[...]
- glvalue 绑定到对虚拟基类的引用(8.5.3),
[...]
如何将glvalue绑定到对虚拟基类的引用并同时引用原始对象?你能提供一个例子吗?
答案 0 :(得分:1)
你正在读错那句话。您引用的项目符号的直接模拟,指向生命周期结束的对象的指针是(§3.8[basic.life] / p5):
- 指针被隐式转换(4.10)为指向虚拟的指针 基类
所以它正在谈论这样的事情:
struct A { };
struct B : virtual A { ~B() {} };
int main() {
B* pb = new B;
B& rb = *pb;
A& ra1 = rb;
pb->~B(); // ends lifetime of *pb
&rb; // OK
A& ra2 = rb; // Undefined behavior. The glvalue rb, referring to an object whose lifetime
// has ended, is bound to a reference to its virtual base class A
A* pa = pb; // Equally undefined
}
答案 1 :(得分:1)
以下似乎是问题的证明:
struct Base {};
struct X : virtual Base {};
int main()
{
X * p = static_cast<X *>(operator new(sizeof X));
Base & r = *p; // *p is an lvalue in the restricted sense
// binding it to a Base & has undefined behaviour
operator delete(p);
}
答案 2 :(得分:1)
考虑对非平凡Derived
对象的引用:使用显式析构函数调用销毁对象,并使用对该对象的引用来访问某些不使用/修改任何状态的函数( glvalue的属性,不依赖于它的值)。由于没有改变内存内容,这仍然是一个有效的操作(只执行了对象的清理)。
无论如何,如果glvalue在>> 之前绑定到一个对象(生命周期初始化结束时开始),那么同样不是这样:如果你有一个Base&
引用并且{{1这是一个虚拟类,它会有所不同:你将通过vtable调用方法/函数,但尚未初始化。未定义的行为。
e.g。
Base