问题描述
在执行此对象的构造函数之前(例如从全局新替换中),在全局名称空间中调用对象的成员函数是否有效且定义良好(不问它是否很漂亮)-当该成员函数执行时,确保该对象的成员变量初始化为零,并且访问(甚至写入)它们没有错误吗? 例如:
#include <iostream>
#include <memory>
using namespace std;
struct A {
A() {
new int();
}
};
A a_;
struct B {
B() : var(10) {
}
void print() {
printf("var is %d\n",var);
var = 5;
}
int var;
};
B b_;
void* operator new(size_t bytes) {
b_.print();
b_.print();
return malloc(bytes);
}
int main()
{
b_.print();
return 0;
}
这将编译并打印
var is 0
var is 5
var is 10
但这是定义的行为吗?
解决方法
确实是零初始化发生在前面,但是在构造非静态类方法的类实例之前调用非静态类方法是未定义的行为。方法调用本身变成未定义的行为。
在同一翻译单元中定义的全局(静态)范围内的对象按其声明顺序构造(并以相反的顺序销毁)。
在这里,a_
首先被构造,然后最终调用new
重载,该重载调用了尚未构造的类实例的方法,这是未定义的行为。
如果两个对象在不同的翻译单元中定义,您将得到static initialization order fiasco。
即使您先定义了b_
,这仍然是未定义的行为,除非您可以保证任何其他翻译单元中的任何内容都不会最终导致此new
重载。这包括C ++库。许多C ++实现的库确实分配了一些存储空间供自己使用,因此,即使定义顺序颠倒了,这也很可能也是未定义的行为。