这是未定义的行为还是误报警告?

Tho*_*mas 8 c++ constructor undefined-behavior clang++

请考虑以下代码:

class A {
private:
  int a;

public:
  A(int a) : a(a) { }
};

class B : public A {
private:
  int b;

  bool init() {
    b = 0;
    return true;
  }

public:
  // init() is a hack to initialize b before A()
  // B() : b(0), A(b) {} yields -Wreorder
  // B() : A((b = 0)) {} no warning (but this one doesn't work so well with non-pod (pointer) types)
  B() : A(init() ? b : 0) {}
};
Run Code Online (Sandbox Code Playgroud)

现在尝试使用clang编译此代码...

$ clang++ test.cpp -fsyntax-only
test.cpp:19:20: warning: field 'b' is uninitialized when used here [-Wuninitialized]
B() : A(init() ? b : 0) {}
                 ^
1 warning generated.
Run Code Online (Sandbox Code Playgroud)

海湾合作委员会不打印任何警告,甚至没有-Wall -Wextra-pedantic.

Bar*_*rry 7

这是未定义的行为.根据[class.base.init]:

在非委托构造函数中,初始化按以下顺序进行:
- 首先,仅针对派生类最多的类(1.8)的构造函数,虚拟基类...
- 然后,直接基类按声明顺序初始化出现在base-specifier-list中(无论mem-initializers的顺序如何).
- 然后,非静态数据成员按照它们在类定义中声明的顺序进行初始化(同样不管mem-initializers的顺序如何).

b在初始化A基类时,不会初始化.由于b = 0同样的原因,赋值本身是未定义的行为 - b在调用时尚未初始化.它的默认构造函数仍将在A构造函数之后调用.

如果你想确保b首先初始化,典型的方法是成员基础成语:

struct B_member {
    int b;
    B_member() : b(0) { }
};

class B : public B_member, public A 
{
public:
    B() : A(b)  // B_member gets initialized first, which initializes b
                // then A gets initialized using 'b'. No UB here.
    { };
};
Run Code Online (Sandbox Code Playgroud)


Col*_*mbo 6

在任何一种情况下,在初始化基类之前调用​​成员函数都会调用未定义的行为.§12.6.2/ 16:

可以为正在构造的对象调用成员函数(包括虚拟成员函数,10.3).类似地,正在构造的对象可以是运算typeid符(5.2.8)或 dynamic_cast(5.2.7)的操作数.但是,如果在基类的所有mem-initializer完成之前,在ctor-initializer(或直接或间接从ctor-initializer调用的函数)中执行这些操作,则操作 的结果是不确定的.[例如:

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

class B : public A {
  int j;
public:
  int f();
  B() : A(f()),  // undefined: calls member function
                 // but base A not yet initialized

  j(f()) { }    // well-defined: bases are all initialized
};
Run Code Online (Sandbox Code Playgroud)

然而,b对它本身的访问和赋值是很好的,因为它具有空的初始化,并且一旦为它获取存储(它在构造函数调用开始之前就已经发生),它的生命周期就开始了.于是

class B : public A {
private:
  int b;

public:
  B() : A(b=0) {}
};
Run Code Online (Sandbox Code Playgroud)

定义明确.