C++内存管理operator new和placement new

电子说

1.3w人已加入

描述

>>> 背景

最近在看一些C++资料的过程中,说到在初始化列表中使用关键字new来分配新内存不是异常安全的,应该使用运算符new。这里就引发了我对C++ new的全新认识。

class A {
public:
    A(int a) : px(new int(a)) {}  // 当然这里基础类是不会异常的
    int* px;
};

>>> 内容

首先我们来回忆一下最常规的new用法。首先创建一个测试类A,并在其构造和析构函数里面打印提示语句。可以发现,在new一个A对象的时候调用了构造函数,在delete一个A对象的时候析构了此对象。而且与C标准库中的malloc函数相比,new关键字不需要知道分配的字节数,而是对类型大小做了自动推断,显然更加方便。

class A {
public:
    A(int a) : _a(a) {
        cout < < "object A(" < < _a < < ") is constructed.n";
    }
    ~A() {
        cout < < "object A(" < < _a < < ") is destructed.n";
    }
    int _a;
};


int main() {
    A* obj = new A(1);
    delete obj;


    return 0;
}
object A(1) is constructed.
object A(1) is destructed.

但是方便的代价就是隐藏了很多细节,从而可能导致使用者在没有充分理解的情况下造成误用。其实关键字new做了非常多的操作。

这里首先给出3个概念,分别是:关键字new、操作符new和放置new(或者说,keywords new、operator new、placement new)。它们之间的关系大概如下所示。

C++语言

当我们使用关键字new去创建一个对象时,会首先根据A类型推断出需要申请的内存字节数,然后再交给operator new去按字节数申请一块可用的内存(否则抛出异常),最后调用类的构造函数创造一个对象保存在申请的这段内存中。

C++语言

而placement new起到的作用是在分配好的内存上创建对象,和operator new有那么一点互补的意思。placement new的引入是为了避免一些频繁的内存申请和回收操作,可以专门申请一块内存做重复的计算,而不是需要一个对象就申请一个内存,从而提高效率。

C++语言

下面是一个比较综合的例子,来表现这些new之间不同。可以看到,我们首先通过operator new来创建一块能够容纳3个A对象的内存空间,然后通过placement new来在这个申请好的内存空间上创建对象,最后使用operator delete把申请的空间销毁。

可以看到operator new不会调用构造函数,operator delete也不会调用析构函数。通过placement new配合起始指针的偏移,可以逐个在新内存上创建有意义的数据对象。

int main() {
    A* mempool = (A*)operator new(sizeof(A) * 3);
    cout < < "Memory is allocated!n";
    A* obj1 = new(mempool) A(1);
    A* obj2 = new(mempool + 1) A(2);
    A* obj3 = new(mempool + 2) A(3);
    cout < < obj1- >_a < < endl;
    cout < < obj2- >_a < < endl;
    cout < < obj3- >_a < < endl;
    operator delete(mempool);
    cout < < obj1- >_a < < endl;
    cout < < obj2- >_a < < endl;
    cout < < obj3- >_a < < endl;


    return 0;
}
Memory is allocated!
object A(1) is constructed.
object A(2) is constructed.
object A(3) is constructed.
1
2
3
35134640
0
1448320

>>> 小结

可以看出,C++在内存分配引入了不少的概念,operator new和operator delete都是可以被自定义类重载的,这就给予了程序员很好的自由度。除了使用new和delete来管理内存外,C++还引入了更为复杂的allocator(或分配器)的概念。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分