c++ - 持有对 Derived 的引用的基类

标签 c++

我想这样做:

struct Derived;

struct Base{
    Derived const& m_ref;
    Base(Derived const& ref) : m_ref(ref){}
};

struct Derived: Base{
    Derived(): Base(*this){}
};

但我似乎得到了不可靠的行为(稍后使用时,m_ref 指向无效派生的事物)。

是否允许在类初始化之前构造对 Derived from *this 的引用?

我知道在初始化之前使用这样的引用是无效的,但我不明白对类初始化的更改会如何影响对它的引用(自初始化以来它不会在内存中四处移动...)。

我不确定如何称呼我正在尝试做的事情,所以我搜索这方面的信息时一片空白......



更新: 我无法用简单的测试用例重现我的问题,所以它看起来可能没问题(虽然我无法证明这一点,但仍然欢迎明确的答案)。 怀疑我的问题是由损坏的复制分配运算符引起的。不过那完全是另一回事!

更新 2 我的复制构造函数和复制赋值运算符确实是罪魁祸首,现在这似乎可以可靠地工作。不过,仍然对它是否是明确定义的行为感兴趣。

最佳答案

3.8/1 说:

The lifetime of an object of type T begins when: — storage with the proper alignment and size for type T is obtained, and — if T is a class type with a non-trivial constructor (12.1), the constructor call has completed.

3.8/5 说:

Before the lifetime of an object has started but after the storage which the object will occupy has been allocated or, after the lifetime of an object has ended and before the storage which the object occupied is reused or released, any pointer that refers to the storage location where the object will be or was located may be used but only in limited ways. Such a pointer refers to allocated storage (3.7.3.2), and using the pointer as if the pointer were of type void*, is well-defined. Such a pointer may be dereferenced but the resulting lvalue may only be used in limited ways, as described below.

“低于”是 3.8/6:

Such an lvalue refers to allocated storage (3.7.3.2), and using the properties of the lvalue which do not depend on its value is well-defined.

...然后是您不能做的事情的列表。绑定(bind)到对相同派生类型的引用不在其中。

我在其他地方找不到任何可能使您的代码无效的东西。值得注意的是,尽管 8.3.2/4 中有以下短语:

A reference shall be initialized to refer to a valid object or function.

似乎没有任何“有效对象”的定义可言。

所以,经过多次来回,我必须得出结论,这是合法的


当然,这并不是说它在任何方面都是一个好主意! 它看起来仍然是一个糟糕的设计。

例如,如果您稍后更改基础构造函数并且以下任何内容变得相关(同样来自 3.8/6):

  • 左值用于访问非静态数据成员或调用对象的非静态成员函数
  • 左值被隐式转换 (4.10) 为对基类类型的引用
  • 左值用作 static_cast 的操作数 (5.2.9)(除非最终转换为 char&unsigned char&
  • 左值用作dynamic_cast (5.2.7) 的操作数或typeid 的操作数。

...那么您的程序将是未定义的,并且编译器可能不会为此发出任何诊断信息!


其他随机观察

在编写此答案时,我注意到其他一些有趣的事情,这里是分享它们的好地方。

首先,9.3.2 似乎意外地未指定 ctor-initializer 中的 this 类型。奇怪!

其次,3.8/5 对指针设置的标准(与我从 3.8/6 引用的列表不同)包括:

If the object will be or was of a non-POD class type, the program has undefined behavior if [..] the pointer is implicitly converted (4.10) to a pointer to a base class type.

我相信这会导致以下看似无害的代码未定义:

struct A {
   A(A* ptr) {}
};

struct B : A {
   B() : A(this) {}
};

int main() {
   B b;
}

关于c++ - 持有对 Derived 的引用的基类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6246365/

相关文章:

c++ - 未找到来自共享库的符号,但已定义

c++ - 由于参数变量中的 %s,sprintf 崩溃

c++ - std::function 与使用 auto 一样高效吗?

c++ - 寻找 "The specified module could not be found"的 dll

c++ - 在最近的封闭范围内使用 using 指令的局部外部变量声明

c++ - C++ 中的相互包含 .. 它是如何工作的?

java - 从 C++ 调用非静态 java 方法时 JNI 访问冲突

c++ - 如何修复从 poco 库收到的异常?

c++ - 如何在默认模板参数中引用自身类型?

c++ - std::stoi 在 MinGW 上的 g++ 4.6.1 中不存在