不带引用计数的智能指针
大约 5 分钟
不带引用计数的智能指针
1. 基础知识
裸指针
int main() {
int* p = new int(10);
*p = 30;
delete p;
return 0;
}
- 如果我们,会造成内存泄漏;
- 或者由于中间程序的执行顺序和我们预想的不一样,导致,导致内存资源泄漏。
堆内存是我们用户手动开辟,手动释放 用不好裸指针也是造成我们内存资源的一种因素
智能指针
智能指针本身是一个类模板,原理利用栈上的对象出作用域会自动析构这么一个特点,把资源释放的代码全部放在这个析构函数中执行,就达到了所谓的智能指针。
//智能指针就是对普通指针的一个封装
template<typename T>
class CSmartPtr
{
public:
CSmartPtr(T *ptr = nullptr) :mptr(ptr) {}
~CSmartPtr() { delete mptr; }
private:
T *mptr;
};
int main()
{
CSmartPtr<int> ptr(new int);
return 0;
}
1)智能指针体现在把裸指针进行了一次面向对象的封装,在构造函数中初始化资源地址,在析构函数中负责释放资源 2)利用栈上的对象出作用域自动析构这个特点,在智能指针的析构函数中保证释放资源
上面的代码实现的是一个简单的智能指针,能够实现内存的自动释放。CSmartPtr<int> ptr(new int);
这行代码中出现了new,可能会有朋友会误认为智能指针是定义在堆(heap)上的。其实不是,。
思考:能不能在堆上定义智能指针? 例如:
CSmartPtr *p = new CSmartPtr(new int)
我们可以看到。智能指针初始化的是一个对象,而不是指针。
- 使用时,我们不能直接把智能指针定义在堆上,这样就没意义了。
#include <iostream>
using namespace std;
template<typename T>
class CSmartPtr
{
public:
CSmartPtr(T* p = nullptr) :ptr(p) {}
~CSmartPtr()
{
delete ptr;
}
T& operator*()
{
return *ptr;
}
T* operator->() //箭头运算符的重载
{
return ptr;
}
private:
T* ptr;
};
class Test
{
public:
void show()
{
cout << "liufeng" << endl;
}
};
int main()
{
CSmartPtr<int>p(new int);
*p = 20;
cout << *p << endl;
CSmartPtr<Test>q(new Test());
q->show();
(q.operator->())->show();
return 0;
}
2. 不带引用计数的智能指针
智能指针使用时,包含#include <memory>
头文件
不带引用计数的智能指针:
- auto_ptr:C++库里面
- scoped_ptr 和 unique_ptr : C++11新标准
不带引用计数的智能指针怎么解决浅拷贝问题?
2.1 auto_ptr
int main()
{
auto_ptr<int> p1(new int);
auto_ptr<int> p2 = p1;
*p1 = 10;
return 0;
}
上面这段代码最终会报错。p1指向了堆上开辟的一块内存,然后用p1拷贝构造p2。我们看了auto_ptr 的源码后得知,auto_ptr 在做拷贝构造函数时,做的是浅拷贝,并且将p2指针指向p1的内存空间,再将。

auto_ptr怎么解决浅拷贝问题?
- 在源码中,不带引用计数,成员变量只有一个裸指针;
- 怎么管理资源的?永远让最后一个智能指针管理资源,前面的智能指针全部被置为nullptr; 这也就造成上面程序的p1不能使用的情况;
容器中不能使用auto_ptr
int main()
{
vector<auto_ptr<int>> vec;
vec.push_back(auto_ptr<int>(new int(10)));
vec.push_back(auto_ptr<int>(new int(20)));
vec.push_back(auto_ptr<int>(new int(30)));
cout << *vec[0] << endl;
vector<auto_ptr<int>> vec2 = vec;
cout << *vec[0] << endl;
return 0;
}
使用容器难免会涉及到容器的拷贝。上面的代码将auto_ptr运用在容器中,第一句cout << *vec[0] << endl;
可以正常打印出10,但是第二句cout << *vec[0] << endl;
无法正确打印。这是由于vector<auto_ptr<int>> vec2 = vec;
。
2.2 scoped_ptr
- 比auto_ptr还暴力,使用的也比较少。
- 直接 将 了;

2.3 unique_ptr
- 不带引用技术的智能指针,推荐使用unique_ptr;
- 定义: 只让一个智能指针管理资源,不会让多个智能指针管理资源(编译报错);
也 将 了:


template<typename T>
unique_ptr<T> getSmartPtr()
{
unique_ptr ptr(new T());
return ptr;
}
int main()
{
unique_ptr<int> p1(new int);
//unique_ptr<int> p2(p1); 不能拷贝构造
unique_ptr<int> p2(std::move(p1)); //转为右值就可以进行拷贝构造了
unique_ptr<int> p3 = getSmartPtr<int>(); // 右边是得到unique_ptr临时对象是右值,故可调用拷贝构造
return 0;
}