智能指针的有关函数使用注意
智能指针分类
- unique_ptr
unique_ptr是个独占指针,C++ 11之前就已经存在,unique_ptr所指的内存为自己独有,某个时刻只能有一个unique_ptr指向一个给定的对象,不支持拷贝和赋值。
#include <iostream>
#include <string>
#include <memory>
#include <vector>
#include <map>
void test()
{
std::unique_ptr<int> up1(new int(11)); // 无法复制的unique_ptr
// unique_ptr<int> up2 = up1; // err, 不能通过编译
std::cout << *up1 << std::endl; // 11
std::unique_ptr<int> up3 = std::move(up1); // 现在p3是数据的唯一的unique_ptr
std::cout << *up3 << std::endl; // 11
// std::cout << *up1 << std::endl; // err, 运行时错误,空指针
up3.reset(); // 显式释放内存
up1.reset(); // 不会导致运行时错误
// std::cout << *up3 << std::endl; // err, 运行时错误,空指针
std::unique_ptr<int> up4(new int(22)); // 无法复制的unique_ptr
up4.reset(new int(44)); // "绑定"动态对象
std::cout << *up4 << std::endl; // 44
up4 = nullptr; // 显式销毁所指对象,同时智能指针变为空指针。与up4.reset()等价
std::unique_ptr<int> up5(new int(55));
int *p = up5.release(); // 只是释放控制权,不会释放内存
std::cout << *p << std::endl;
// cout << *up5 << endl; // err, 运行时错误,不再拥有内存
delete p; // 释放堆区资源
return;
}
- shared_ptr
shared_ptr允许多个该智能指针共享“拥有”同一堆分配对象的内存,这通过引用计数(reference counting)实现,会记录有多少个shared_ptr共同指向一个对象,一旦最后一个这样的指针被销毁,也就是一旦某个对象的引用计数变为0,这个对象会被自动删除。支持复制和赋值操作。
#include <iostream>
#include <string>
#include <memory>
#include <vector>
#include <map>
void test()
{
std::shared_ptr<int> sp1(new int(22));
std::shared_ptr<int> sp2 = sp1;
std::cout << "cout: " << sp2.use_count() << std::endl; // 打印引用计数, 2
std::cout << *sp1 << std::endl; // 22
std::cout << *sp2 << std::endl; // 22
sp1.reset(); // 显示让引用计数减一
std::cout << "count: " << sp2.use_count() << std::endl; // 打印引用计数, 1
std::cout << *sp2 << std::endl; // 22
return;
}
- weak_ptr
weak_ptr是为配合shared_ptr而引入的一种智能指针来协助shared_ptr工作,它可以从一个shared_ptr或另一个weak_ptr对象构造,它的构造和析构不会引起引用计数的增加或减少。没有重载 *和 -> 但可以使用lock获得一个可用的shared_ptr对象。
weak_ptr的使用更为复杂一点,它可以指向shared_ptr指针指向的对象内存,却并不拥有该内存,而使用weak_ptr成员lock,则可返回其指向内存的一个share_ptr对象,且在所指对象内存已经无效时,返回指针空值nullptr。
weak_ptr并不拥有资源的所有权,所以不能直接使用资源。 可以从一个weak_ptr构造一个shared_ptr以取得共享资源的所有权。
weak_ptr解决shared_ptr循环引用的问题
class CB;
class CA
{
public:
CA() { cout << "CA() called! " << endl; }
~CA() { cout << "~CA() called! " << endl; }
void set_ptr(shared_ptr<CB>& ptr) { m_ptr_b = ptr; }
void b_use_count() { cout << "b use count : " << m_ptr_b.use_count() << endl; }
void show() { cout << "this is class CA!" << endl; }
private:
shared_ptr<CB> m_ptr_b;
};
class CB
{
public:
CB() { cout << "CB() called! " << endl; }
~CB() { cout << "~CB() called! " << endl; }
void set_ptr(shared_ptr<CA>& ptr) { m_ptr_a = ptr; }
void a_use_count() { cout << "a use count : " << m_ptr_a.use_count() << endl; }
void show() { cout << "this is class CB!" << endl; }
private:
shared_ptr<CA> m_ptr_a;
};
void test_refer_to_each_other()
{
shared_ptr<CA> ptr_a(new CA());
shared_ptr<CB> ptr_b(new CB());
cout << "a use count : " << ptr_a.use_count() << endl;
cout << "b use count : " << ptr_b.use_count() << endl;
ptr_a->set_ptr(ptr_b);
ptr_b->set_ptr(ptr_a);
cout << "a use count : " << ptr_a.use_count() << endl;
cout << "b use count : " << ptr_b.use_count() << endl;
}
// 测试结果
CA() called!
CB() called!
a use count : 1
b use count : 1
a use count : 2
b use count : 2
shared_from_this()函数
c++11中的shared_from_this()来源于boost中的enable_shared_form_this类和shared_from_this()函数,功能为返回一个当前类的std::share_ptr。
当类A被share_ptr管理,且在类A的成员函数里需要把当前类对象作为参数传给其他函数时,就需要传递一个指向自身的share_ptr。
我们就使类A继承enable_share_from_this,然后通过其成员函数share_from_this()返回当指向自身的share_ptr。
class A : public enable_shared_from_this<A> {
public:
weak_ptr<A> Func() {
return shared_from_this();
}
};
-
把当前类对象作为参数传给其他函数时,为什么要传递share_ptr呢?直接传递this指针不可以吗?
一个裸指针传递给调用者,谁也不知道调用者会干什么?假如调用者delete了该对象,而share_tr此时还指向该对象。 -
这样传递share_ptr可以吗?share_ptr
这样会造成2个非共享的share_ptr指向一个对象,最后造成2次析构该对象
//错误示例,最后会报错
#include <memory>
#include <iostream>
class Bad
{
public:
std::shared_ptr<Bad> getptr() {
return std::shared_ptr<Bad>(this);
}
~Bad() { std::cout << "Bad::~Bad() called" << std::endl; }
};
int main()
{
// 错误的示例,每个shared_ptr都认为自己是对象仅有的所有者
std::shared_ptr<Bad> bp1(new Bad());
std::shared_ptr<Bad> bp2 = bp1->getptr();
// 打印bp1和bp2的引用计数
std::cout << "bp1.use_count() = " << bp1.use_count() << std::endl;
std::cout << "bp2.use_count() = " << bp2.use_count() << std::endl;
} // Bad 对象将会被删除两次
//正确示例
#include <memory>
#include <iostream>
struct Good : std::enable_shared_from_this<Good> // 注意:继承
{
public:
std::shared_ptr<Good> getptr() {
return shared_from_this();
}
~Good() { std::cout << "Good::~Good() called" << std::endl; }
};
int main()
{
// 大括号用于限制作用域,这样智能指针就能在system("pause")之前析构
{
std::shared_ptr<Good> gp1(new Good());
std::shared_ptr<Good> gp2 = gp1->getptr();
// 打印gp1和gp2的引用计数
std::cout << "gp1.use_count() = " << gp1.use_count() << std::endl;
std::cout << "gp2.use_count() = " << gp2.use_count() << std::endl;
}
system("pause");
}
demo测试是否真正理解
#include<iostream>
using namespace std;
class A : public enable_shared_from_this<A> {
public:
weak_ptr<A> Func() {
return shared_from_this();
}
};
int main() {
auto a = make_shared<A>();//1对
//unique_ptr<A> a(new A);//2错
//A* a = new A;//3错
//auto a = make_unique<A>();//4错
//shared_ptr<A> a(new A);//5对
a->Func();
return 0;
}
这里面只有1和5是可以运行的
原因:调用shared_from_this()函数,必须要求对象是一个被智能指针shared_ptr管理的对象。