C++ 我可以使用C++;在初始值设定项列表中初始化的类成员,在列表的后面?

C++ 我可以使用C++;在初始值设定项列表中初始化的类成员,在列表的后面?,c++,instantiation,class-constructors,podofo,C++,Instantiation,Class Constructors,Podofo,我正在重写一些代码以消除全局变量,并使类构造函数/析构函数处理某些第三方库资源的清理,但我担心的是一些代码会从类初始化器列表中的另一个成员初始化一个成员 class MyPodofoDocument { public: // generates pdf to stream MyPodofoDocument(std::stringstream *pStringStream) : device(pStringStream), document(&device)

我正在重写一些代码以消除全局变量,并使类构造函数/析构函数处理某些第三方库资源的清理,但我担心的是一些代码会从类初始化器列表中的另一个成员初始化一个成员

class MyPodofoDocument {
public:
    // generates pdf to stream
    MyPodofoDocument(std::stringstream *pStringStream)
        : device(pStringStream), document(&device)
    {
    }
private:
    PoDoFo::PdfOutputDevice device;
    PoDoFo::PdfStreamedDocument document;
    PoDoFo::PdfPainter painter;
};
使用该类的代码不需要查看使用该库所需的所有详细信息,但我隐藏它们的方式使它依赖于使用成员来初始化其他成员,然后才命中构造函数的实际代码块,在该代码块中它有一个有效的this指针


它是在单元测试框架中工作的,所以我的问题基本上是,“这样可以吗,便携的,安全的?”

。规则是按照类声明中声明的顺序初始化成员变量

在您的情况下,这很好,因为
设备
是在
文档
之前声明的

然而,在下面的例子中,我们有未定义的行为,尽管初始化列表的顺序不同

class A {
public:
  A(int i) : b(i), a(b) { }
private:
  int a;
  int b;
}

成员按声明顺序从上到下初始化

PoDoFo::PdfOutputDevice device;
PoDoFo::PdfStreamedDocument document;
PoDoFo::PdfPainter painter;

因此,使用
设备
来初始化
文档

是安全的,尽管只要变量之间的依赖关系与声明顺序相同就安全,但这不是很好的做法。这类代码应该尽可能避免,因为在重构类时很容易错误地修改声明顺序,从而触发UB,正如Alex的示例所示。换句话说,这是正确的,但非常脆弱。@syam:我不太确定。。。我以前也这么认为,但是如果初始值设定项出现问题(编译器会提醒您注意潜在的UB),编译器很容易提醒您,在某些情况下,引用同一类型的不同成员可能会有所帮助;任何变量之间存在真正依赖关系的地方,但也需要存储变量的地方。@DavidRodríguez dribeas你是对的,我刚用g++4.7检查过它有
-Wreorder
(包含在
-Wall
中)抓住了这种情况。我不知道,我以前使用的旧编译器没有这种警告,旧习惯很难改掉。此外,获取地址或将引用绑定到尚未构建的成员是合法的(即,如果接收者不使用对象,但只存储引用/指针,则可以将引用传递给稍后声明的成员).传递是合法的,但在语义上是错误的,因为传递的是指向尚未构造的对象的指针。@Alex Chamberlain:不一定有问题,但可能需要仔细检查。如果您是指针的使用者,您如何判断?@Alex-您必须小心!标准库的流类当
streambuf
尚未构造时,将指向其
streambuf
成员的指针指向流的基类构造函数。当然,基类知道它应该只存储指针供以后使用,并且只在构造完成后使用。