C++ 动态内存分配和智能指针 share_ptr/unique_ptr

目录

1、动态对象以及new/delete

2、智能指针


1、动态对象以及new/delete

C++除了在代码编译时创建的自动(auto)和静态(static)对象外,还支持运行过程中动态分配对象,动态对象只有显式地被释放时,这些对象才会销毁。

C++中使用 new/delete 运算符完成动态内存管理,new在动态空间中为对象分配空间并返回指向该对象的指针,delete接受一个动态对象指针,销毁该对象,并释放与之关联的内存。传递给delete的指针必须指向动态分配的内存,或者是一个空指针,释放一块非new分配的内存,或者将相同的指针释放多次,其行为是未定义的。

为防止空悬指针的出现(指曾经保存一个对象但现在已经释放的内存,空悬指针引起的程序错误难以调试,delete后的指针就变成空悬指针),delete之后最好用nullptr重置指针。

关于 deletedelete[] 的方法:delete 后加方括号 [] 用于在析构时逐个调用数组中的元素的析构函数完成对象数组的析构。一般来说用于析构由 new[] 分配的内存,如下:

class A{
public:
    int *p;
    A(){
        p = new int[10];
    }
    ~A(){
        delete[] p;
    }
}
// 定义十个A对象的对象指针数组
A *a = new A[10];
// 释放a所指向的内存
delete[] a;

上述代码中每一个类对象在定义一个对象时都会初始化一个指向指定动态分配的内存空间的指针,在析构函数中释放相应的内存空间,因此在释放指向A对象的指针数组时需要使用 [] 来逐个调用数组中对象的析构函数来释放相应的内存。如果 delete 后不加 [] 的话就相当于只调用一次析构函数。

动态对象的正确释放是编程中极其容易出错的地方。为了更安全地使用动态对象,标准库定义了两个智能指针类型来管理动态分配的对象。当一个对象应该被释放时,指向它的智能指针可以确保自动地释放它。

2、智能指针

为了更容易同时更安全地使用动态内存,新的标准库提供了两种智能指针(smart pointer)类型shared_ptr unique_ptr 来管理动态内存,类型定义在 <memory> 头文件中。智能指针的行为类似常规指针,重要区别在于他们可以负责自动释放所指向的对象。shared_ptr 允许多个指针指向同一对象,unique_ptr 则“独占”所指向的对象。

1、shared_ptr

与vector一样,智能指针也是模板,因此创建一个智能指针时,必须提供指针可以指向的类型信息,声明可以类似于:

shared_ptr<string> p1;

shared_ptr支持拷贝(将一个shared_ptr赋给另一个shared_ptr)和赋值(给shared_ptr赋予新值)操作。每个shared_ptr都有一个关联的计数器,通常称为引用计数(reference count。无论何时我们拷贝一个shared_ptr,计数器都会递增,例如用一个shared_ptr初始化另一个shared_ptr时,或将它作为参数传给一个函数以及作为函数的返回值时。当我们给shared_ptr赋予一个新值或是shared_ptr被销毁(如一个局部的shared_ptr离开作用域)时,计数器就会递减。

一旦一个shared_ptr的计数器变为0,他就会自动释放自己管理的对象(通过shared_ptr类的析构函数完成自动释放对象及其关联的内存)。如:

auto r = make_shared<int>(42);  // r指向的int只有一个引用者
r = q; // 给r赋值,令他指向另外一个地址,递增q指向的对象的引用计数,递减r原来指向的对象的引用计数,此时r原来指向的对象已经没有引用者,会自动释放

2、unique_ptr

某个时刻只能有一个unique_ptr指向一个给定对象。当unique_ptr被销毁时,它所指向的对象也会被销毁。

与shared_ptr不同,unique_ptr没有类似make_shared的标准库函数返回一个unique_ptr。当我们定义一个unique_ptr时,需要将其绑定到一个new返回的指针上,类似shared_ptr,初始化unique_ptr必须采用直接初始化形式(注意第三行是个错误的示例):

unique_ptr<double> p1;  // 指向一个double的unique_ptr
unique_ptr<int> p2(new int(42));  // p2指向一个值为42的int
unique_ptr<int> p2 = new int(42);  // 错误!必须使用直接初始化形式

3、weak_ptr

weak_ptr是一种不控制所指向对象生存期的智能指针,他指向由一个shared_ptr管理的对象。将一个weak_ptr绑定到一个shared_ptr不会改变shared_ptr的引用计数。一旦最后一个指向对象的shared_ptr被销毁,对象就会被释放。即使有weak_ptr指向对象,对象还是会被释放,因此weak_ptr的名字抓住了智能指针“弱”共享对象的特点。

猜你喜欢

转载自blog.csdn.net/Flag_ing/article/details/125131526