是否明确定义了未初始化对象的成员地址?

时间:2018-04-25 18:22:07

标签: c++ language-lawyer object-lifetime ctor-initializer member-access

考虑以下示例。构造bar时,它为其基类型(foo)构造函数提供my_member.y的地址,其中my_member是尚未初始化的数据成员。

struct foo {
    foo(int * p_x) : x(p_x) {}
    int * x;
};

struct member {
    member(int p_y) : y(p_y) {}
    int y;
};

struct bar : foo
{
    bar() : foo(&my_member.y), my_member(42) {}
    member my_member;
};

#include <iostream>

int main()
{
    bar my_bar;
    std::cout << *my_bar.x;
}

这个定义得很好吗?获取未初始化对象的数据成员的地址是否合法?我发现this question关于传递对未初始化对象的引用,但它并不完全相同。在这种情况下,我在未初始化的对象上使用member access operator .

确实不应该通过初始化来更改对象的数据成员的地址,但这并不一定使 该地址定义良好。此外,member access operators上的ccpreference.com页面可以这样说:

  

即使没有必要,也会评估两个运算符的第一个操作数(例如,当第二个操作数命名为静态成员时)。

我理解这意味着在&my_member.y my_member的情况下会被评估,我相信这很好(就像int x; x;似乎很好)但我找不到文档支持那个。

2 个答案:

答案 0 :(得分:6)

首先让我们准确地说出问题。

您正在做的是没有使用未初始化的对象,您正在使用不在其生命周期内的对象。 my_member是在foo之后构建的,因此my_member的生命周期尚未在foo(&my_member.y)开始。

来自[basic.life]

  

在对象的生命周期开始之前但在对象将占用的存储空间被分配之后[...],可以使用引用原始对象的任何glvalue,但只能以有限的方式使用。 [...]这样的glvalue指的是已分配的存储空间,并且使用不依赖于其值的glvalue的属性是明确定义的。如果出现以下情况,该程序具有未定义的行为:

     
      
  • glvalue用于访问对象,或[...]
  •   

此处访问它意味着要么读取或修改对象的值。

my_member的评估产生左值,并且没有必要转换为prvalue,因此它保持左值。同样,my_member.y的评估也是左值。然后我们得出结论,没有访问任何对象的值,这是明确定义的。

答案 1 :(得分:2)

是的,您可以将&my_member.y传递给foo的构造函数,甚至可以复制指针 - 您使用x(p_x)执行此操作。

解除引用上{@ 1}}构造函数中指针的行为未定义。 (但你不这样做。)