C++静态函数内通过构造函数创建对象的疑问与原理分析
关于C++静态函数中通过构造函数创建对象的疑问解答
首先来看你提供的代码:
class A { public: A() { this->a = 50; std::cout << "constructor called... " << this << std::endl; setAddr(this); } ~A() { this->a = 10; std::cout << "destructor called... " << this << std::endl; } int a; static A* addr; static void setAddr(A* ad) { addr = ad; } static A &create() { A(); return *addr; } }; A* A::addr = NULL; int main() { A &ptr = A::create(); std::cout << "a = " << ptr.a << std::endl; ptr.a = 100; std::cout << "a = " << ptr.a << std::endl; getch(); return 0; }
程序运行输出:
constructor called... 009AF874
destructor called... 009AF874
a = 10
a = 100
下面逐一解答你的疑问:
疑问1:我并未通过A obj;这类声明创建对象,为何析构函数会被调用?
你在create()静态函数里写的A();其实是创建了一个临时对象。在C++规则里,临时对象的生命周期极其短暂——它会在所在的表达式执行完成后立即被销毁。当create()中的A();这行代码执行结束时,这个临时对象的作用域就到头了,所以编译器会自动调用它的析构函数,这就是你看到析构输出的原因。
疑问2:既然析构函数已被调用,为何我还能成功给ptr.a赋值?
这其实是典型的未定义行为场景。你返回的*addr是对已经被销毁的临时对象内存的引用——临时对象销毁后,它占用的内存并没有被操作系统立刻回收或者覆盖,所以你暂时还能读取甚至修改这块内存里的内容。但这种情况完全是不可靠的:后续任何内存分配、函数调用都可能覆盖这块区域,导致程序崩溃或者出现完全不可预测的结果。你现在能成功赋值只是“运气好”,绝对不能依赖这种写法。
关于你的结论补充
你的两个结论有一定道理,但需要更准确的表述:
- 结论1:构造函数确实在对象内存分配完成后调用,对象的销毁时机由其作用域决定。这里的临时对象作用域仅限于
A();这个表达式,表达式执行完毕就会触发析构。 - 结论2:对象地址在销毁前被存在
addr中,但返回的引用指向的是已经被释放的内存。你能操作这块内存只是因为它还没被复用,但这属于C++标准明确禁止的未定义行为,实际开发中绝对不能这么写。
内容的提问来源于stack exchange,提问作者Alok
相关产品推荐
相关产品推荐

