C++基础教程面向对象(学习笔记(89))

本文探讨了智能指针的概念,包括std::unique_ptr、std::shared_ptr和std::weak_ptr,以及它们在C++中如何帮助管理动态分配的资源。文章详细介绍了复制语义与移动语义的区别,以及std::move如何实现移动语义。此外,还提供了代码示例,展示了如何使用std::make_shared和std::make_unique遵循最佳实践。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

综合检测

智能指针类是一个组合类,用于管理动态分配的内存,并确保在智能指针对象超出范围时删除内存。

复制语义允许复制我们的类。这主要通过复制构造函数和复制赋值运算符完成。

移动语义意味着一个类将转移对象的所有权而不是复制。这主要通过移动构造函数和移动赋值运算符完成。

std :: auto_ptr已弃用,应避免使用。

r值引用是用于使用r值初始化的引用。使用双符号创建r值参考。编写带有r值引用参数的函数很好,但是你几乎不应该返回r值引用。

如果我们构造一个对象或做一个参数是l值的赋值,我们唯一能合理做的就是复制l值。我们不能假设改变l值是安全的,因为它可能会在程序的后期再次使用。如果我们有一个表达式“a = b”,我们就不会合理地期望b以任何方式改变。

但是,如果我们构造一个对象或进行一个参数为r值的赋值,那么我们就知道r值只是某种临时对象。我们可以简单地将其资源(便宜)转移到我们正在构建或分配的对象上,而不是复制它(这可能很昂贵)。这是安全的,因为临时的将在表达式的末尾被销毁,所以我们知道它永远不会被再次使用!

您可以使用delete关键字通过删除复制构造函数和复制赋值运算符来禁用您创建的类的复制语义。

std :: move允许您将l值视为r值。当我们想要在l值上调用移动语义而不是复制语义时,这很有用。

std :: unique_ptr是您应该使用的智能指针类。它管理单个不可共享的资源。应该首选std :: make_unique()(在C ++ 14中)来创建新的std :: unique_ptr。std :: unique_ptr禁用复制语义。

std :: shared_ptr是您需要多个对象访问同一资源时使用的智能指针类。在管理它的最后一个std :: shared_ptr被销毁之前,资源不会被销毁。应首选std :: make_shared()来创建新的std :: shared_ptr。使用std :: shared_ptr,应该使用复制语义来创建指向同一对象的附加std :: shared_ptr。

std :: weak_ptr是当你需要一个或多个能够查看和访问由std :: shared_ptr管理的资源的对象时使用的智能指针类,但与std :: shared_ptr不同,在确定是否不考虑std :: weak_ptr时资源应该被销毁。

Quiz Time:

1)解释何时应使用以下类型的指针。

1a)std :: unique_ptr

解决方案

当您希望智能指针管理不会被共享的动态对象时,应使用std :: unique_ptr。
1b)std :: shared_ptr

解决方案

当您希望智能指针管理可共享的动态对象时,应使用std :: shared_ptr。在所有持有对象的std :: shared_ptr被销毁之前,不会释放该对象。
1c)std :: weak_ptr

解决方案

当您想要访问由std :: shared_ptr管理的对象时,应该使用std :: weak_ptr,但不希望std :: shared_ptr的生命周期与std :: weak_ptr的生命周期相关联。
1d)std :: auto_ptr

解决方案

不推荐使用std :: auto_ptr,并在C ++ 17中删除它。不应该使用它。
2)解释r值引用如何启用移动语义。

解决方案

因为r值是临时的,所以我们知道它们在使用后会被破坏。当按值传递或返回r值时,制作副本然后销毁原件是浪费的。相反,我们可以简单地移动(窃取)r值的资源,这通常更有效。
3)以下代码有什么问题?更新程序以符合最佳实践。
3A)

#include <iostream>
#include <memory> //std::shared_ptr
 
class Resource
{
public:
	Resource() { std::cout << "Resource acquired\n"; }
	~Resource() { std::cout << "Resource destroyed\n"; }
};
 
int main()
{
	Resource *res = new Resource;
	std::shared_ptr<Resource> ptr1(res);
	std::shared_ptr<Resource> ptr2(res);
 
	return 0;
}

解决方案

ptr2是从res而不是从ptr1创建的。这意味着您现在有两个std :: shared_ptr,每个都独立地尝试管理资源(他们彼此不了解)。当一个人超出范围时,另一个将留下一个悬空指针。
应该从ptr1而不是res复制ptr2,并且应该使用std :: make_shared()

#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 ptr1 = std::make_shared<Resource>();
	auto ptr2(ptr1);
 
	return 0;
}

3B)

#include <iostream>
#include <memory> // std::shared_ptr
 
class Something; //假设Something是一个可以抛出异常的类
 
int main()
{
	doSomething(std::shared_ptr<Something>(new Something), std::shared_ptr<Something>(new Something));
 
	return 0;
}

解决方案

如果Something的构造函数抛出异常,则其中一个Somethings可能无法正确释放。
解决方案是使用make_shared:

#include <iostream>
#include <memory> //  std::shared_ptr
 
class Something; // 假设Something是一个可以抛出异常的类
 
int main()
{
	doSomething(std::make_shared<Something>(), std::make_shared<Something>());
 
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值