关于 C++构造函数的一个疑问

2018-06-19 10:22:54 +08:00
 paparika

class Test1;

class Test2{ public: Test2(Test1* t1){

}

};

class Test1{ public: Test1():p(new Test2(this)){}//方法 1

//Test1(){p = new Test2(this);}//方法 2

Test2 *p;

};

使用方法 1 来构造,会不会有问题? 我的意思是当 new Test2(this)在执行时,能否确保传入的 this 已经是构造完毕的,比如说 Test2 的构造函数需要读取 Test1 对象的成员,假如这个 this 不是构造完毕的,其成员也是不确定的,那么 new 出来的 Test2 自然也有问题

2237 次点击
所在节点    C
8 条回复
sanjusss
2018-06-19 10:30:28 +08:00
需要看你的初始化顺序。Test2 访问在它之前已经初始化的 Test1 成员就没有问题。比较典型的是 Qt 里的 QObject。
paparika
2018-06-19 10:36:21 +08:00
两个方法效率上有差异吗
geelaw
2018-06-19 10:39:47 +08:00
成员初始化的顺序是成员在类 /结构中声明的顺序。

既可以选择 Test2 只访问 Test1 中已经初始化好的部分,也可以选择先把 p 设置为 nullptr,再交给 Test2 的构造函数。通常来说 p 是 nullptr 也不算是业务逻辑上初始化好的状态,所以 either way 你都需要 Test1、Test2 耦(内)合(聚)。

但如果 p 是 nullptr 的情况下 Test1 也算是业务逻辑上初始化好的状态,那么倾向于先初始化为这样,再变更为有一个 Test2 的情况。
gnaggnoyil
2018-06-19 10:41:18 +08:00
注意区分 allocate 和 construct 的区别.`new Test2(this)`在执行的时候`this`显然尚未被 construct,所以此时如果你在`Test2`的 constructor 里使用了 Test1 的成员那就相当于读取了一个未初始化的 object 那肯定是未定义行为……

不过具体到 LZ 这种写法反倒不需要关心这种问题:`Test2::Test2(Test1 *)`的函数体是在类内定义的所以此时`Test1`只有声明没有定义,因此`Test2::Test2(Test1 *)`的函数体内肯定没法使用`Test1`的成员,否则就是编译错误.
paparika
2018-06-19 10:45:59 +08:00
嗯,我就是想确认下那个确实是未定义状态
seancheer
2018-06-19 11:05:34 +08:00
http://www.cs.technion.ac.il/users/yechiel/c++-faq/using-this-in-ctors.html

在构造函数 body 里面是没有问题的,这个时候成员已经被初始化
但是初始化列表中可能会访问到未初始化的成员。

另外,多说一句,构造方法中,父类使用子类 override 的 virtual 方法时,可能无法访问到子类 override 的方法。
sfqtsh
2018-06-19 11:21:45 +08:00
这样写有危险。
zh5e
2018-06-19 13:57:22 +08:00
1. 看构造函数有哪些逻辑,这个时候对象内存已经分配好了,成员变量没有相互引用来初始化就没关系
2. 构造函数执行过程中,this 指向的对象肯定没有构造完成

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/463997

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX