广汉做网站,行业门户网站有什么作用,什么是网店,长治网站建设推广智能指针是存储指向动态分配#xff08;堆#xff09;对象指针的类。用于生存期控制#xff0c;能够确保在离开指针所在作用域时#xff0c;自动正确的销毁动态分配的对象#xff0c;防止内存泄漏。它的一种通用实现技术是使用引用计数。美使用它一次#xff0c;内部的引… 智能指针是存储指向动态分配堆对象指针的类。用于生存期控制能够确保在离开指针所在作用域时自动正确的销毁动态分配的对象防止内存泄漏。它的一种通用实现技术是使用引用计数。美使用它一次内部的引用计数加1每析构一次内部引用计数减1减为0时删除所指向的堆内存。
shared_ptr共享的智能指针 std::shared_ptr使用引用计数每一个shared_ptr的拷贝都指向相同的内存。在最后一个shared_ptr析构的时候内存才会被释放。
shared_ptr的基本用法
初始化 可以通过构造函数std::make_sharedT辅助函数和reset方法来初始化shared_ptr代码如下
#include memory
#include iostream
using namespace std;int main()
{std::shared_ptrint p(new int(1));std::shared_ptrint p2 p;std::shared_ptrint ptr;ptr.reset(new int(1));if (ptr){cout ptr is not null endl;}///编译报错不允许直接赋值///std::shared_ptrint p4 new int(1);return 0;
} 我们应该优先使用make_shared来构造智能指针因为它更加高效。 不能将一个原始指针直接赋值给一个指针指针例如下面这种方法是错误的
///编译报错不允许直接赋值
std::shared_ptrint p new int(1); 可以看到智能指针的用法和普通指针的用法类似只不过不需要自己管理分配的内存。shared_ptr不能通过直接将原始指针赋值来初始化需要通过构造函数和辅助方法来初始化。对于一个未初始化的智能指针可以通过reset方法来初始化当智能指针中有值的时候调用reset会使引用计数减1。另外智能指针可以通过重载的bool类型符来判断智能智能中是否为空未初始化。
获取原始指针 当需要获取原始指针时可以通过get方法来返回原始指针代码如下
#include memory
#include iostream
#include string
using namespace std;int main()
{std::shared_ptrint p(new int(1));int* pp p.get();cout *pp endl;std::shared_ptrstring pstr(new string(hello world));auto ppstr pstr.get();cout *ppstr endl;return 0;
}
指定删除器 智能指针初始化可以指定删除器代码如下
#include memory
#include iostream
#include string
#include string.h
using namespace std;typedef struct Message
{char* ptr;int i;double db;
}Message;void DeletePtr(Message* pm)
{cout pm-i endl;cout pm-db endl;cout pm-ptr endl;if (pm-ptr){delete [] pm-ptr;pm-ptr nullptr;}
}int main()
{Message* m new Message;m-db 2.8;m-i 1;m-ptr new char[100];memset(m-ptr, 0, 100);char* ptr (char*)hello world;strncpy(m-ptr, ptr, strlen(ptr));std::shared_ptrMessage p(m, DeletePtr);///std::shared_ptrMessage pp(m, [](Message* pm){if (pm-ptr) { cout pm-ptr endl; delete [] pm-ptr;}});return 0;
} 当p的引用计数为0时自动调用删除器DeletePtr来释放对象的内存。删除器可以是一个lambda表达式因此上面的写法还可以改为
std::shared_ptrMessage pp(m, [](Message* pm){if (pm-ptr) { cout pm-ptr endl; delete [] pm-ptr;}});
使用shared_ptr需要注意的问题 智能指针虽然能自动管理堆内存但是它哟不少缺陷在使用时需要注意。 1、不要用一个原始指针初始化多个shared_ptr例如下面这些是错误的
int* ptr new int;
shared_ptrint p1(ptr);
shared_ptrint p2(ptr); ///logic error 2、不要在函数实参中创建shared_ptr对于下面的写法是错误的
function(shared_ptrint(new int), g()); 因为C的函数参数的计算顺序在不同的编译器不同的调用约定下可能是不一样的一般是从右到左但也有可能是从左到右所以可能的过程是先new int然后调用g()如果恰好g()发生异常而shared_ptrint还没有创建则int内存泄漏正确的写法是先创建智能指针代码如下
shared_ptrint p(new int);
f(p, g()); 3、通过shared_from_this()返回this指针。不要将this指针作为shared_ptr返回出来因为this指针本质上是一个裸指针因此这样可能会导致重复析构看下面的代码
#include memory
#include iostream
#include string
#include string.h
using namespace std;struct A
{shared_ptrA GetSelf(){return shared_ptrA(this);}///析构函数调用了2次~A(){cout delete A endl;}
};int main()
{shared_ptrA sp1(new A);shared_ptrA sp2 sp1-GetSelf();return 0;
} 在这个例子中由于用同一个指针this构造了两个智能指针sp1和sp2而他们之间是没有任何关系的在离开作用域之后this将会被构造的两个智能指针各自析构导致重复析构的错误。 正确返回this的shared_ptr的做法是让目标类通过派生std::enable_shared_thisT类然后使用基类的成员函数shared_from_this来返回this的shared_ptr看下面的代码
#include memory
#include iostream
#include string
#include string.h
using namespace std;struct A : public std::enable_shared_from_thisA
{shared_ptrA GetSelf(){return shared_from_this();}///析构函数调用了1次~A(){cout delete A endl;}
};int main()
{shared_ptrA sp1(new A);shared_ptrA sp2 sp1-GetSelf();return 0;
} 4、要避免循环引用。指针指针最大的一个陷阱是循环引用循环引用会导致内存泄漏。下面是一个典型的循环引用的场景。
#include memory
#include iostream
#include string
#include string.h
using namespace std;struct A;
struct B;struct A
{std::shared_ptrB bptr;~A(){cout A is deleted endl;}
};struct B
{std::shared_ptrA aptr;~B(){cout B is deleted endl;}
};int main()
{{///析构函数没有被调用shared_ptrA ap(new A);shared_ptrB bp(new B);ap-bptr bp;bp-aptr ap;}return 0;
} 测试结果是两个指针A和B都不会被删除存在内存泄漏。循环引用导致ap和bp引用计算器为2在离开作用域之后ap和bp的引用计数器减为1并不会为0导致两个指针不会被析构产生了内存泄漏。