智能指针类是一种组合类,专门用于管理动态分配的内存,并在智能指针对象离开作用域时确保该内存被释放。
拷贝语义允许我们的类被复制,主要通过拷贝构造函数和拷贝赋值运算符实现。
移动语义意味着类将转移对象的所有权,而非进行复制,主要通过移动构造函数和移动赋值运算符完成。
std::auto_ptr 已被弃用,应避免使用。
右值引用是一种专为接受右值而设计的引用,使用双与号(&&)声明。虽然可以编写以右值引用为形参的函数,但几乎绝不应返回右值引用。
如果我们用左值构造对象或执行赋值,唯一能合理执行的操作就是复制该左值——我们无法安全地修改它,因为程序后续可能还要使用。例如表达式 a = b 中,我们绝不会期望 b 被改变。
然而,如果我们用右值构造对象或执行赋值,则该右值只是某种临时对象。此时与其进行(可能昂贵的)复制,不如将其资源(以低廉的成本)直接转移给正在构造或赋值的对象。这样做是安全的,因为临时对象在表达式结束时就会被销毁,我们确信它再也不会被使用!
可使用关键字 delete 显式禁用类的拷贝语义:将拷贝构造函数与拷贝赋值运算符标记为已删除即可。
std::move 允许将左值“视”为右值,从而在左值上触发移动语义而非拷贝语义。
std::unique_ptr 应是你首选的智能指针。它管理唯一的、不可共享的资源。创建新的 std::unique_ptr 时,应优先使用 C++14 引入的 std::make_unique()。std::unique_ptr 禁止拷贝语义。
std::shared_ptr 用于需要多个对象共享同一资源的场景。仅当最后一个管理该资源的 std::shared_ptr 被销毁时,资源才会被释放。创建新的 std::shared_ptr 时,应优先使用 std::make_shared()。对于已存在的对象,应使用拷贝语义创建指向同一对象的额外 std::shared_ptr。
std::weak_ptr 用于需要查看或访问由 std::shared_ptr 管理之资源的情形;与 std::shared_ptr 不同的是,在决定是否销毁资源时,std::weak_ptr 不计入引用计数。
测验
请说明以下指针类型应在何时使用:
1a) std::unique_ptr
展示解答
1b) std::shared_ptr
展示解答
1c) std::weak_ptr
展示解答
1d) std::auto_ptr
展示解答
请解释为何移动语义围绕右值展开。
展示解答
下列代码存在哪些问题?请将其改写为符合最佳实践的版本。
3a)
#include <iostream>
#include <memory> // for std::shared_ptr
class Resource
{
public:
Resource() { std::cout << "Resource acquired\n"; }
~Resource() { std::cout << "Resource destroyed\n"; }
};
int main()
{
auto* res{ new Resource{} };
std::shared_ptr<Resource> ptr1{ res };
std::shared_ptr<Resource> ptr2{ res };
return 0;
}