2

我有一个 Parent 类,它接受两个引用,这些引用可能实际上是对同一事物的引用,也可能不是。在这种情况下,当它们相同时,我会在 Child 类的初始化程序列表中收到序列点警告:

class A
{
  public:
    A(int) {}
  private:
    A() {}
};

class Parent
{
  public:
    Parent(A&, A&) {}
};

class Child : public Parent
{
  public:
    Child() :
      Parent(
          *(_A = new A(0)),
          *(_A)) //Warning on this line
  {
  }

  private:
    A *_A;
};

int main(int argc, char** argv)
{
  return 0;
}

我猜这是因为在分配内存后不能保证该行上的取消引用。无论如何,我的问题是,在不更改父级或 A 的情况下,是否存在这种情况?

4

1 回答 1

4

你是对的,父构造函数的两个参数被调用的顺序是不能保证的(它们之间没有序列点),所以编译器可以在计算*(_A)之前合法地计算*(_A = new A(0))

是否需要动态分配A?如果没有,你可以这样做:

class Child : public Parent
{
  public:
    Child() : Parent( _a, _a ), _a(0) {}
  private:
    A _a;               // _A is reserved for the implementation (compiler + library)
};

需要注意的是,虽然获取成员的地址或对其进行引用是有效的,但在成员初始化之前使用该引用或指针是未定义的行为_a,这只会在Parent构造函数完成后发生。也就是说,只要Parent's 的构造函数只存储引用但不使用你是安全的对象(沿着刀片的边缘骑行,但没有流血)。

如果Parent构造函数将引用用于存储以外的任何内容,则可以更改Child类以接收指向已构造A对象的指针:

Child::Child( A* a ) : Parent( *a, *a ), _a(a) {}
于 2012-04-24T22:47:37.703 回答