当智能指针过期时,其析构函数将使用delete来释放内存,因此如果将new返回的地址给这些对象,将无需记住稍后释放这些内存

包含头文件 <memory>

所有智能指针都有一个explicit的构造函数

#include <bits/stdc++.h> 
#include <initializer_list>
#include <memory>
#include <vector>
using namespace std;

class Test {
public:
	Test(initializer_list<int> p) {
		for (auto &it:p) {
			v.push_back(it);
		}
	}
	vector<int> v;

	~Test() {
		cout << "Deconstructed" << endl;
	}
};

int main() {    
    ios_base::sync_with_stdio(false); 
    cin.tie(NULL); 
    cout.tie(NULL); 

	shared_ptr<Test> p(new Test(
		{1, 2, 3, 4, 5}
	));

	for (auto &it : p->v) {
		cout << it << ',';
	}
	return 0;
}

auto_ptr

在[[C++]]11中已经被弃用

std::auto_ptr 实现了所有权转移的语义,即当 std::auto_ptr 被复制或赋值时,所有权会从一个对象转移到另一个对象。这意味着源对象在复制或赋值操作之后不再拥有对象的所有权,并且会变为空(null)

std::auto_ptr<int> p1(new int(10));
std::auto_ptr<int> p2 = p1; // p1 被复制到 p2,p1 不再拥有对象的所有权
// 现在 p1 为空,只有 p2 拥有对象的所有权

shared_ptr

std::shared_ptr 提供了共享所有权语义,允许多个智能指针共享同一个对象的所有权,并使用引用计数来管理对象的生命周期

unique_ptr

std::unique_ptr 提供了独占所有权语义,并且禁止复制操作,从而避免了 std::auto_ptr 的所有权转移问题。

不能被复制,但可以通过std::move转移所有权。

(但是存在特例!如果源unique_ptr是一个临时的右值,编译器允许复制)

#include <iostream>
#include <memory>

std::unique_ptr<int> createUniquePtr() {
    return std::make_unique<int>(10); // 返回一个临时的unique_ptr
}

int main() {
    std::unique_ptr<int> p1 = createUniquePtr(); // 移动构造,允许从临时右值移动
    std::cout << *p1 << std::endl; // 输出 10

    std::unique_ptr<int> p2 = std::make_unique<int>(20);
    // std::unique_ptr<int> p3 = p2; // 错误,不能复制
    std::unique_ptr<int> p4 = std::move(p2); // 移动构造,允许从左值移动
    std::cout << *p4 << std::endl; // 输出 20

    return 0;
}

make_unique 与 new 比较

std::make_unique可以防止由于new操作符可能引发的内存泄漏问题

std::make_unique提供了强异常安全性。如果在构造过程中抛出异常,它能够确保没有内存泄漏,因为内存分配和构造是一个原子操作。

相对来说,new的异常安全性较差

  • 在复杂表达式中,如果new操作符成功分配内存,但在构造std::unique_ptr对象之前抛出异常,可能会导致内存泄漏