c++智能指针及其实现

博客介绍了C++中智能指针类引用计数的实现方法。通过一个辅助类,其成员函数私有,仅智能指针类可操作。智能指针类将计数器与指向对象关联,在创建、复制、赋值和析构对象时,对引用计数进行相应增减操作,以管理对象内存。

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

 

使用一个辅助类,成员函数全部私有,对智能指针类友元,只有智能指针类可以对其操作,辅助类含有两个数据成员:计数count与基础对象指针(模板)

智能指针类用引用计数来实现,将一个计数器与类指向的对象相关联,引用计数跟踪共有多少个类对象共享同一指针。具体做法如下:

  1. 当创建类的新对象时,初始化指针,并将引用计数设置为1
  2. 当对象作为另一个对象的副本时,复制构造函数复制副本指针,并增加与指针相应的引用技术(加1)
  3. 使用赋值操作符对一个对象进行赋值时,先使左操作数的指针的引用计数减1(因为指针已经指向别的地方),如果减1后引用计数为0,则释放指针所指对象内存,然后增加右操作数所指对象的引用计数(因为此时做操作数指向对象即右操作数指向对象)
  4. 析构函数:调用析构函数时,析构函数先使引用计数减1 ,如果减至0则delete对象。
#pragma once
#include "common.h"
template <typename T>
class SmartPtr;

template <typename T>
//基础对象类
class Point
{
public:
	Point(int xVal = 0, int yVal = 0) :x(xVal), y(yVal) { }
	int getX() const { return x; }
	int getY() const { return y; }
	void setX(int xVal) { x = xVal; }
	void setY(int yVal) { y = yVal; }

private:
	int x, y;

};
template <typename T>

class U_Ptr //辅助类用以封装使用计数与基础对象指针。
{
private:

	//该类成员访问权限全部为private,因为不想让用户直接使用该类
	friend class SmartPtr<T>; //定义智能指针类为友元,因为智能指针类需要直接操纵辅助类
	//构造函数的参数为基础对象的指针
	U_Ptr(T* ptr) :p(ptr), count(1) { }
	~U_Ptr() { delete p; }

	int count;
	T* p;
};

template <typename T>
class SmartPtr //智能指针类
{
public:
	SmartPtr(T* ptr) :rp(new U_Ptr<T>(ptr)) { }

	SmartPtr(const SmartPtr<T>& sp) :rp(sp.rp) { ++rp->count; }

	SmartPtr& operator=(const SmartPtr<T>& rhs) {//重载赋值操作符
		++rhs.rp->count;//首先将右操作数引用计数加1,
		if (--rp->count == 0)//然后将引用计数减1,可以应对自赋值
			delete rp;
		rp = rhs.rp;
		return *this;
	}
	T& operator *()        //重载*操作符  
	{
		return *(rp->p);
	}
	T* operator ->()       //重载->操作符  
	{
		return rp->p;
	}
	~SmartPtr() {
		if (--rp->count == 0)//当引用计数减为0时,删除辅助类对象指针,从而删除基础对象
			delete rp;
		else
			cout << "还有" << rp->count << "个指针指向基础对象" << endl;
	}

private:
	U_Ptr<T>* rp;//辅助类对象指针
};

使用

int* i = new int(2);
		{
			SmartPtr<int> ptr1(i);
			{
				SmartPtr<int> ptr2(ptr1);
				{
					SmartPtr<int> ptr3 = ptr2;

					cout << *ptr1 << endl;
					*ptr1 = 20;
					cout << *ptr2 << endl;

				}
			}
		}
		system("pause");

结果:

参考:https://www.cnblogs.com/qg-whz/p/4777312.html

<think>嗯,用户想了解C++智能指针的概念和底层实现,包括unique_ptr、shared_ptr和weak_ptr的原理和应用场景。首先,我需要回忆智能指针的基本概念。智能指针是用来管理动态内存,自动释放资源,防止内存泄漏的RAII机制。C++11引入了这几个指针来替代有问题的auto_ptr。 接下来,每个指针的具体实现。unique_ptr是独占所有权的,内部应该有一个指针,并且在析构时删除对象。可能需要禁用拷贝构造和赋值,使用移动语义转移所有权。shared_ptr使用引用计数,每个对象维护一个控制块,记录引用数。构造时增加计数,析构时减少,当计数为零时释放内存。weak_ptr不增加引用计数,用来解决循环引用的问题,它需要从shared_ptr构造,访问对象时需要转为shared_ptr。 然后应用场景。unique_ptr适用于单一所有权的资源,比如动态数组或工厂模式返回的对象。shared_ptr适用于多个对象共享资源的情况,比如缓存中的对象。weak_ptr用于观察shared_ptr管理的资源,避免循环引用,比如在观察者模式中。 还要注意底层实现细节,比如shared_ptr的控制块可能包含强引用和弱引用的计数。weak_ptr的实现需要能够访问shared_ptr的控制块,但不影响强引用计数。此外,循环引用的例子,比如两个互相持有shared_ptr,导致计数无法归零,这时候需要用weak_ptr来打破循环。 用户提供的引用中提到了weak_ptr的构造函数和赋值操作符的实现,以及不能直接将原始指针赋值给智能指针。这些需要结合到回答中,说明实现时的注意事项,比如使用get()方法获取原始指针,以及构造时的正确方法。 可能还需要比较不同智能指针的区别,比如unique_ptr和shared_ptr的所有权机制,weak_ptr如何协助shared_ptr工作。同时,要提到为什么auto_ptr被弃用,因为它有所有权转移的语义问题,容易导致悬挂指针。 最后,应用场景的举例要具体,比如在缓存中使用shared_ptr,当需要观察缓存中的对象是否存在时使用weak_ptr。在异常安全方面,智能指针如何确保资源释放。 总结时,要确保覆盖概念、原理、实现和应用,同时结合用户提供的引用内容,正确引用标记,并生成相关问题。</think>### C++ 智能指针详解 #### 一、核心概念 智能指针C++中基于**RAII(资源获取即初始化)**机制的内存管理工具,通过对象生命周期自动管理堆内存。其核心目标是**防止内存泄漏**和**简化资源管理**。C++11标准引入的三种智能指针分别为: - `unique_ptr`:独占所有权 - `shared_ptr`:共享所有权 - `weak_ptr`:观察共享资源 #### 二、底层实现原理 1. **`unique_ptr`** - **所有权机制**:通过禁用拷贝构造函数和赋值运算符(声明为`= delete`),仅允许移动语义转移所有权[^2] - **内部结构**: ```cpp template<typename T> class unique_ptr { T* ptr; // 裸指针 // 禁止拷贝构造和赋值 unique_ptr(const unique_ptr&) = delete; unique_ptr& operator=(const unique_ptr&) = delete; }; ``` - **应用场景**:工厂模式返回值、动态数组管理(支持`unique_ptr<T[]>`) 2. **`shared_ptr`** - **引用计数**:通过控制块(control block)维护两个计数器: - 强引用计数:管理对象生命周期 - 弱引用计数:管理控制块生命周期 - **内存结构**: $$ \begin{array}{|c|c|} \hline \text{对象指针} & \text{控制块} \\ \hline \uparrow & \downarrow \\ \text{shared_ptr1} & \text{强引用计数=2} \\ \text{shared_ptr2} & \text{弱引用计数=1} \\ \hline \end{array} $$ - **线程安全**:引用计数操作为原子操作,但对象访问需额外同步[^1] 3. **`weak_ptr`** - **观测机制**:不增加强引用计数,需通过`lock()`转为`shared_ptr`访问资源 - **实现关键**: ```cpp template<class T> class weak_ptr { T* _ptr; // 资源指针 ControlBlock* cb; // 指向shared_ptr的控制块 }; ``` - **构造限制**:必须从`shared_ptr`或另一个`weak_ptr`构造 #### 三、应用场景对比 | 型 | 所有权模式 | 典型应用场景 | |--------------|---------------------|-----------------------------| | `unique_ptr` | 独占所有权 | 文件句柄管理、工厂模式返回值 | | `shared_ptr` | 共享所有权 | 对象缓存、多线程共享资源 | | `weak_ptr` | 无所有权(仅观察) | 解决循环引用、缓存观察器 | #### 四、循环引用示例 ```cpp class B; class A { public: shared_ptr<B> b_ptr; }; class B { public: shared_ptr<A> a_ptr; // 改为weak_ptr可解决循环引用 }; ``` #### 五、核心操作限制 - **禁止原始指针直接赋值**: ```cpp shared_ptr<int> sp = new int(5); // 错误[^3] shared_ptr<int> sp(new int(5)); // 正确 ``` - **weak_ptr有效性检查**: ```cpp if (auto spt = weak_ptr.lock()) { // 安全访问资源 } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值