最近,我发现了一个有趣的讨论,关于如何允许对私有成员进行只读访问而不会使用多个getter模糊设计,其中一个建议就是这样做:
#include <iostream> class A { public: A() : _ro_val(_val) {} void doSomething(int some_val) { _val = 10*some_val; } const int& _ro_val; private: int _val; }; int main() { A a_instance; std::cout << a_instance._ro_val << std::endl; a_instance.doSomething(13); std::cout << a_instance._ro_val << std::endl; }
输出:
$./a.out 0 130
GotW#66明确指出对象的生命周期开始
when its constructor completes successfully and returns normally. That is,control reaches the end of the constructor body or an earlier return statement.
如果是这样,我们无法保证在执行_ro_val(_val)时正确创建_val memeber.那么上面的代码怎么工作呢?是不确定的行为?或者原始类型是否为对象的生命周期赋予了一些异常?
任何人都可以指点一些可以解释这些事情的参考吗?
解决方法
在调用构造函数之前,如果在本地存储上创建对象,则为Freestore上的对象(如果使用new)或堆栈保留适当的内存量.这意味着_val的内存已经在成员初始化列表中引用时分配,只是该内存尚未正确初始化.
_ro_val(_val)
使引用成员_ro_val引用为_val分配的内存,这可能实际上包含此时的任何内容.
您的程序中仍然存在未定义的行为,因为您应该在构造函数体/成员初始化列表中将_val显式初始化为0(或者您选择的某个值).在这种情况下输出0只是因为您很幸运它可能会给出你有一些其他的值,因为_val未被初始化.请参阅gcc 4.3.4上的行为here,它演示了UB.
但至于问题,是的,行为确实很明确.