原理:
智能指针是一个类,这个类的构造函数中传入一个普通指针,析构函数中释放传入的指针。智能指针的类都是栈上的对象,所以当函数(或程序)结束时会自动被释放。方便管理堆内存。
智能指针是利用RAII(资源获取即初始化)技术对普通指针进行封装,使智能指针实质是一个对象,行为表现的像一个指针。
常用的智能指针:
1、shared_ptr:
基于引用计数的智能指针。可随意赋值,当内存引用计数为0时内存被释放。支持多个指针指向相同的对象。shared_ptr内部的引用计数是线程安全的,但是对象的读取需要加锁。
初始化:智能指针是模板类,可以指定类型,传入指针通过构造函数初始化。也可以使用make_shared函数初始化。不能将指针直接赋值给一个智能指针,因为智能指针是类,不能用指针赋值。
例如:std::shared_ptr<int> p4 = new int(1);
写法错误
拷贝和赋值:拷贝使对象的引用计数加1,赋值使原对象(左侧)引用计数减1,新对象(右侧)引用计数加1,当计数为0时,自动释放内存。
get函数:获取原始指针,不要用一个原始指针初始化多个shared_ptr,否则会造成二次释放同一内存。
#include <iostream>
#include <memory>
int main() {
{
int a = 10;
std::shared_ptr<int> ptra = std::make_shared<int>(a);
std::shared_ptr<int> ptra2(ptra); //copy
std::cout << ptra.use_count() << std::endl; // 2
int b = 20;
int *pb = &a;
//std::shared_ptr<int> ptrb = pb; // error 不能用指针赋值类
std::shared_ptr<int> ptrb = std::make_shared<int>(b);
ptra2 = ptrb; // assign ptra2由ptra位置变为指向ptrb
pb = ptrb.get(); // 获取原始指针
std::cout << ptra.use_count() << std::endl; // 1
std::cout << ptrb.use_count() << std::endl; // 2
}
}
2、unique_ptr:
“唯一”拥有所指对象。同一时刻只能有一个unique_ptr指向给定对象,禁止拷贝语义、只有移动语义。在出现异常的情况下,动态资源能得到释放。
创建:通过构造函数指定
重新指定:reset方法
释放所有权:release方法
移动语义转移所有权:std::move
#include <iostream>
#include <memory>
int main() {
{
std::unique_ptr<int> uptr(new int(10)); //绑定动态对象
//std::unique_ptr<int> uptr2 = uptr; //不能赋值,编译出错
//std::unique_ptr<int> uptr2(uptr); //不能拷贝
std::unique_ptr<int> uptr2 = std::move(uptr); //转移所有权,uptr无效指针
uptr2.release(); //释放所有权
}
/超过uptr的作用域,內存释放
}
3、weak_ptr:
弱引用,只引用,不计数,没有重载operator*和->,对shared_ptr资源观测。针对shared_ptr互相引用形成环(循环引用),两个指针指向的内存都无法释放的问题。需要手动打破循环引用或使用weak_ptr。
构造:从一个shared_ptr或者另一个weak_ptr对象构造。
观测资源的引用计数:成员函数use_count()。
被观测的资源是否存在:成员函数expired(),功能等价于use_count()==0,但更快。
从被观测的shared_ptr获得一个可用的shared_ptr对象:成员函数lock(), 操作资源。当expired()==true的时候,lock()函数返回一个存储空指针的shared_ptr。
注意:如果一块内存被shared_ptr和weak_ptr同时引用,所有shared_ptr析构后,不管还有没有weak_ptr引用该内存,内存也会被释放。所以weak_ptr不保证它指向的内存一定是有效的,在使用之前需要检查weak_ptr是否为空指针。
#include <iostream>
#include <memory>
int main() {
{
std::shared_ptr<int> sh_ptr = std::make_shared<int>(10);
std::cout << sh_ptr.use_count() << std::endl; // 1
std::weak_ptr<int> wp(sh_ptr);
std::cout << wp.use_count() << std::endl; // 1
if(!wp.expired()){
std::shared_ptr<int> sh_ptr2 = wp.lock(); //get another shared_ptr
*sh_ptr = 100;
std::cout << wp.use_count() << std::endl; // 2
}
}
//delete memory
}
循环引用例子如下:
错误例子:
#include <iostream>
#include <memory>
class Child;
class Parent;
class Parent {
private:
std::shared_ptr<Child> ChildPtr;
public:
void setChild(std::shared_ptr<Child> child) {
this->ChildPtr = child;
}
void doSomething() {
if (this->ChildPtr.use_count()) {
}
}
~Parent() {
}
};
class Child {
private:
std::shared_ptr<Parent> ParentPtr;
public:
void setPartent(std::shared_ptr<Parent> parent) {
this->ParentPtr = parent;
}
void doSomething() {
if (this->ParentPtr.use_count()) {
}
}
~Child() {
}
};
int main() {
std::weak_ptr<Parent> wpp;
std::weak_ptr<Child> wpc;
{ // {}代表作用域,出作用域以下p和c应该被销毁
std::shared_ptr<Parent> p(new Parent); // 1
std::shared_ptr<Child> c(new Child); // 1
p->setChild(c); // 2
c->setPartent(p); // 2
wpp = p;
wpc = c;
std::cout << p.use_count() << std::endl; // 2
std::cout << c.use_count() << std::endl; // 2
} // 出作用域时对象p和c没销毁,每个count只减少一次
std::cout << wpp.use_count() << std::endl; // 1
std::cout << wpc.use_count() << std::endl; // 1
return 0;
}
正确做法:
#include <iostream>
#include <memory>
class Child;
class Parent;
class Parent {
private:
//std::shared_ptr<Child> ChildPtr;
std::weak_ptr<Child> ChildPtr;
public:
void setChild(std::shared_ptr<Child> child) {
this->ChildPtr = child;
}
void doSomething() {
//new shared_ptr
if (this->ChildPtr.lock()) {
}
}
~Parent() {
}
};
class Child {
private:
std::shared_ptr<Parent> ParentPtr;
public:
void setPartent(std::shared_ptr<Parent> parent) {
this->ParentPtr = parent;
}
void doSomething() {
if (this->ParentPtr.use_count()) {
}
}
~Child() {
}
};
int main() {
std::weak_ptr<Parent> wpp;
std::weak_ptr<Child> wpc;
{
std::shared_ptr<Parent> p(new Parent); // 1
std::shared_ptr<Child> c(new Child); // 1
p->setChild(c); // c = 1
c->setPartent(p); // p = 2
wpp = p;
wpc = c;
std::cout << p.use_count() << std::endl; // 2
std::cout << c.use_count() << std::endl; // 1
} // c只有1,1-->0,销毁c对象时调用child的析构函数,会对p销毁一次,而p对象本身会销毁一次,所以也是0
std::cout << wpp.use_count() << std::endl; // 0
std::cout << wpc.use_count() << std::endl; // 0
return 0;
}
智能指针实现:
#include <iostream>
#include <memory>
template<typename T>
class SmartPointer {
private:
T* _ptr;
size_t* _count;
public:
SmartPointer(T* ptr = nullptr) : _ptr(ptr) {
if (_ptr) {
_count = new size_t(1);
} else {
_count = new size_t(0);
}
}
SmartPointer(const SmartPointer& ptr) {
if (this != &ptr) {
this->_ptr = ptr._ptr;
this->_count = ptr._count;
(*this->_count)++;
}
}
SmartPointer& operator=(const SmartPointer& ptr) {
if (this->_ptr == ptr._ptr) {
return *this;
}
if (this->_ptr) {
(*this->_count)--;
if (*this->_count == 0) {
delete this->_ptr;
delete this->_count;
}
}
this->_ptr = ptr._ptr;
this->_count = ptr._count;
(*this->_count)++;
return *this;
}
T& operator*() {
assert(this->_ptr == nullptr);
return *(this->_ptr);
}
T* operator->() {
assert(this->_ptr == nullptr);
return this->_ptr;
}
~SmartPointer() {
(*this->_count)--;
if (*this->_count == 0) {
delete this->_ptr;
delete this->_count;
}
}
size_t use_count(){
return *this->_count;
}
};
int main() {
{
SmartPointer<int> sp(new int(10));
SmartPointer<int> sp2(sp);
SmartPointer<int> sp3(new int(20));
std::cout << sp.use_count() << std::endl;
std::cout << sp3.use_count() << std::endl;
sp2 = sp3;
std::cout << sp.use_count() << std::endl;
std::cout << sp3.use_count() << std::endl;
}
//delete operator
}
网友评论