- C++保证一定会在 main() 函数之前构造出全局对象,在 main() 函数结束之前把全局对象摧毁掉。这是静态的初始化操作和内存释放操作。
- C++中所有的全局对象都放在程序的 data segment 中。如果明确给它一个值,对象将以该值为初值,否则对象所配置到的内存内容全为 0。包括 POD类型,这个C语言不一样。在C中专门有 .bss 段来存放未初始化的全局变量。
- cfront 采用 munch 策略保证全局对象的构造与析构,有三部曲:
- 为所有的需要静态初始化的档案产生一个__sti() 函数,内带必要的 constructor 调用操作或 inline expansions。
- 在所有需要静态的内存释放操作的文件中,产生一个__std()函数(static deallocation),内带必要的 destructor 操作,或是其 inline expansions。
- 提供一组 runtime library “munch” 函数:一个 _main() 函数(用以调用可执行文件中所有的 __sti() 函数),以及一个 exit() 函数(以类似方式调用所有 __std() 函数。
如图:
- 对于对象数组,cfront 中采用 vec_new() 函数初始化数组中的对象,你可以显示初始化某几个对象,那么其他对象或许会默认构造初始化或者由于 trivial 什么也不做。
- 对于:point *ptr = new point3d[10]; 这种多态申请对象数组,如果直接 delete[] ptr,可能不会触发多态(亲测:gcc直接 core dump)。所以必须进行强制转换,使用delete[] static_cast<point3d*>(ptr);
- placement new 不分配内存,只调用构造函数。所以要提前申请好内存,防止段错误。
- placement new 在一个原已存在的对象上构造新对象,而该对象有一个析构函数,这个析构函数并不会调用。所以需要显示将原有对象销毁掉,但是不能直接 delete,因为直接 delete 会将内存也释放掉,所以必须显示调用析构函数(STL的 destroy 函数就是这么处理placement new 的)即可。如:p2w->~point2w(); p2w = new(arena) point2w;
- C++中类似 T c = a + b,编译器优化后不会产生临时对象,但是赋值语句 c = a + b,不能够忽略临时对象,因为该表达式期待左端有一次析构操作,所以左端必须先析构,此时的 a + b 的结果会用 __temp0 来保存,左端完成析构后,再进行赋值。
- 在一个表达式中(比如各种与或非),临时对象的摧毁,应该是对完整表达式求值过程中的最后一个步骤。
- 临时对象的销毁有两个特例:
- 临时对象作为赋值语句的右值,必须等到左值对象初始化完成后才销毁(此时会进行拷贝构造)。
- 临时对象被引用绑定了,那么它的销毁会知道引用的生命结束,或者直到临时对象的生命周期结束——视哪种情况先到达而定。
附录:
有关定位 new 的知识,来自知乎:
作者:蓝色
但是,暴露出来的delete expression却只有两个出来: 也就是用于
非数组与数组的delete。
也就是用于非数组与数组的delete。
接下来举一个例子来说明一下这个构造函数发生异常的时候,调用 placement delete function的情况:
结果如下:
如果你是在placement new上面工作,你如果delete以后,你也把placement new上面的内存释放了,这往往不是你想要的结果。举个例子:
Point* p = new (arena) Point;
// do something
// manipulate a new object
delete p; // Wrong. You release the arena memory
p = new (arena) Point;
// correct method
p->~P();
p = new (arena) Point;
而这里,你说有没有placement delete?
placement delete expression是绝对没有的东西。但是有一个placement delete
function,而不是placement delete expression。而这个placement delete function是你
直接调用不到的东西。当placement new expression调用placement new function,如果构造函数
函数构造的时候发生了异常,这个时候要防止内存泄露,那么要
清理掉已分配的内存,就需要这个placement delete function。而这个东西的定义你可以打开<new>头文件看到。
![](https://i-blog.csdnimg.cn/blog_migrate/579aa68433e7408587659a529bff2a62.png)
![](https://i-blog.csdnimg.cn/blog_migrate/577543e0017fa00afee6565fb77f41bb.png)
接下来举一个例子来说明一下这个构造函数发生异常的时候,调用 placement delete function的情况:
#include <cstdlib>
#include <iostream>
struct A {} ;
struct E {} ;
class T
{
public:
T() { throw E() ; }
} ;
void * operator new ( std::size_t, const A & )
{
void* nothing = 0;
std::cout << "Placement new called." << std::endl;
return nothing;
}
void operator delete ( void *, const A & )
{
std::cout << "Placement delete called." << std::endl;
}
int main ()
{
A a ;
try {
T * p = new (a) T ;
} catch (E exp) {std::cout << "Exception caught." << std::endl;}
return 0 ;
}
结果如下:
![](https://i-blog.csdnimg.cn/blog_migrate/16d431f53f756d0fe48d8d2356d92a38.png)