2013-02-19 91 views
6

我正在重写一些代码以消除全局变量,并且让一个构造函数/析构函数处理某些第三方库资源的清理,但是我担心一些代码会从类初始化程序列表中的其他成员初始化一个成员。我可以使用初始化器列表中初始化的C++类成员,稍后在列表中吗?

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; 
}; 

使用这个类并不需要看到所有进入使用库的详细信息的代码,但我隐瞒他们的方式使得它依赖于使用成员初始化其他成员,它击中前构造函数的实际代码块,它有一个有效的指针。

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

回答

8

的成员在顺序进行初始化声明它们,从上到下

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

因此它是安全的使用device初始化document

+0

此外,获取地址或将引用绑定到尚未构建的成员是合法的(即,如果接收者不使用*对象,但只存储引用/指针)。 – 2013-02-19 20:48:25

+0

传递是合法的,但在语义上是错误的,因为你将一个指针传递给尚未构造的东西。 – 2013-02-19 20:53:13

+0

@AlexChamberlain:它一定没有错,但可能需要重新检查。 – GManNickG 2013-02-19 21:12:04

4

的种类。规则是成员变量按照它们在类声明中声明的顺序进行初始化。

对您而言,自devicedocument之前宣布无误。

但是,在下面的情况下,尽管初始化程序列表的顺序仍然存在未定义的行为。

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

即使它是安全的*只要变量之间的依赖关系与声明顺序*相同,恕我直言,这不是很好的做法。这样的代码应该尽可能避免,因为在重构你的课程时错误地修改声明顺序太容易了,从而触发UB,正如Alex的例子所显示的那样。换句话说,这是正确的,但非常脆弱。 – syam 2013-02-19 20:24:06

+1

@syam:我不太确定......我曾经这么想过,但如果初始化程序失灵,编译器会很容易地警告您(编译器会将您的注意力引向潜在的UB)在某些情况下,它可能有助于引用同一类型的不同成员。 – 2013-02-19 20:49:51

+0

它不仅适用于相同类型的课程,任何存在变量之间真正依赖关系的东西,但也需要存储变量的地方。 – 2013-02-19 20:51:20

相关问题