|版本声明:山河君,未经博主允许,禁止转载
系列文章目录
文章目录
前言
C++ 这门编程语言的历史可以追溯至 1979 年,当时的 Bjarne Stroustrup(C++ 之父,后续简称 Stroustrup)还在使用 Simula 语言进行开发工作。
1998 年,C++ 标准委员会发布了第一版 C++ 标准,并将其命名为 C++ 98 标准。据不知名人士透露,《带注释的C++参考手册》这本书对 C++ 98 标准的制定产生了很大的影响。
经过作者的不断迭代,一本书往往会先后发布很多个版本,其中每个新版本都是对前一个版本的修正和更新。C++ 编程语言的发展也是如此。截止到目前(2020 年),C++ 的发展历经了以下 3 个个标准:
2011 年,新的 C++ 11 标准诞生,用于取代 C++ 98 标准。
2014 年,C++ 14 标准发布,该标准库对 C++ 11 标准库做了更优的修改和更新;
2017 年底,C++ 17 标准正式颁布;
虽然学习 C++11 需要花些时间,但这是非常值得的;C++11 非常实用,它不但提高了开发效率,还让程序更加健壮和优雅。程序员应该乐于升级换代已有的知识,而学习和使用 C++11 早就是大势所趋。
一、shared_ptr介绍
1.shared_ptr特点
相对于unique_ptr持有对象独有权,即保证保证同一时间内只有一个智能指针可以指向该对象。
shared_ptr实现共享式拥有,即多个智能指针可以指向相同对象,该对象和其相关资源会在“最后一个引用(reference)被销毁”时候释放。
2.原理
(1)通过使用引用计数机制,shared_ptr可以共享所有权,但是这回产生额外的开销。
(2)shared_ptr 对象除了包括一个所拥有对象的指针外, 还包括一个引用计数代理对象的指针,用于进行计数。
(3)了保证线程安全性,引用计数器的加1,减1操作都是 原子操作,它保证 shared_ptr 由多个线程共享时不会爆掉。
(4)同样重载了解除引用运算符(*)和成员选择运算符(->)。
通俗来讲:就是说多个shared_ptr在管理同一个指针时,都会引用同一个计数器。每增加一个share_ptr管理该指针,计数器就会+1,每减少一个share_ptr,计数器就会-1;当计数器为0时,此时才会释放指针所指向的资源。
二、shared_ptr使用
1.构造以及简单使用
#include <iostream>
#include <vector>
using namespace std;
class Test {
public:
Test() {
str = "hello world";
cout << "init" << endl;
}
void print()
{
cout << str << endl;
}
~Test()
{
cout << "realse" << endl;
}
private:
string str;
};
int main()
{
Test* test = new Test;
shared_ptr<Test> p1(test);
shared_ptr<Test> p2 = p1;
(*p1).print();
(*p2).print();
return 0;
}
结果:可以看到shared_ptr可以互相赋值,并且每个shared_ptr都可以使用,而在最后进行释放
2.常用方法
(1)use_count 返回引用计数的个数
(2)unique 返回是否是独占所有权( use_count 为 1)
(3)swap 交换两个 shared_ptr 对象(即交换所拥有的对象)
(4)reset 放弃内部对象的所有权或拥有对象的变更, 会引起原有对象的引用计数的减少
(5)get 返回内部对象(指针)
int main()
{
Test* test = new Test;
shared_ptr<Test> p1(test);
cout << p1.use_count() << endl; //返回1
shared_ptr<Test> p2 = p1;
cout << p1.use_count() << endl; //返回2
cout << p2.use_count() << endl; //返回2
return 0;
}
3.错误用法
(1)存在两个计数器,会引起对同一块内存释放两次,发生段错误
int main()
{
Test* test = new Test;
shared_ptr<Test> p1(test);
shared_ptr<Test> p2(test);
return 0;
}
(2)循环引用,导致内存泄漏
#include <iostream>
#include <vector>
using namespace std;
class Test2;
class Test1 {
public:
Test1() {
cout << "init" << endl;
}
~Test1()
{
cout << "realse" << endl;
}
public:
shared_ptr<Test2> p1;
};
class Test2 {
public:
Test2() {
cout << "init" << endl;
}
~Test2()
{
cout << "realse" << endl;
}
public:
shared_ptr<Test1> p2;
};
int main()
{
shared_ptr<Test1> p1(new Test1());
shared_ptr<Test2> p2(new Test2());
(*p1).p1 = p2;
(*p2).p2 = p1;
cout << p1.use_count() << endl;
cout << p2.use_count() << endl;
return 0;
}
结果:可以看到并没有自动释放内存,这是由于 test1和 test2对象互相引用,它们的引用计数都是 1,不能自动释放,并且此时这两个对象再无法访问到。这就引起“内存泄漏”。
要解决这类问题就要使用weak_ptr
三、weak_ptr介绍
1.weak_ptr特点
weak_ptr 是一种不控制对象生命周期的智能指针, 它指向一个 shared_ptr 管理的对象. 进行该对象的内存管理的是那个强引用的 shared_ptr. weak_ptr只是提供了对管理对象的一个访问手段。
2.使用weak_ptr目的
weak_ptr 设计的目的是为配合 shared_ptr 而引入的一种智能指针来协助 shared_ptr 工作, 它只可以从一个 shared_ptr 或另一个 weak_ptr 对象构造, 它的构造和析构不会引起引用记数的增加或减少。
四、weak_ptr的使用
1.方法
(1)weak_ptr 没有重载*和->但可以使用 lock 获得一个可用的 shared_ptr 对象.。注意, weak_ptr 在使用前需要检查合法性。
(2)expired 用于检测所管理的对象是否已经释放, 如果已经释放, 返回 true; 否则返回 false.
(3)lock 用于获取所管理的对象的强引用(shared_ptr). 如果 expired 为 true, 返回一个空的 shared_ptr; 否则返回一个 shared_ptr, 其内部对象指向与 weak_ptr 相同。
(4)use_count 返回与 shared_ptr 共享的对象的引用计数。
(5)reset 将 weak_ptr 置空。
(6)weak_ptr 支持拷贝或赋值, 但不会影响对应的 shared_ptr 内部对象的计数。
2.使用实例
(1)针对shared_ptr错误用法2,把类中shared_ptr改为weak_ptr
#include <iostream>
#include <vector>
using namespace std;
class Test2;
class Test1 {
public:
Test1() {
cout << "init" << endl;
}
~Test1()
{
cout << "realse" << endl;
}
public:
weak_ptr<Test2> p1;
};
class Test2 {
public:
Test2() {
cout << "init" << endl;
}
~Test2()
{
cout << "realse" << endl;
}
public:
weak_ptr<Test1> p2;
};
int main()
{
shared_ptr<Test1> p1(new Test1());
shared_ptr<Test2> p2(new Test2());
(*p1).p1 = p2;
(*p2).p2 = p1;
cout << p1.use_count() << endl;
cout << p2.use_count() << endl;
return 0;
}
结果:可以看到计数器都为1
(2)查看是否释放,如果弱引用智能指针没有释放,则获取
int main()
{
shared_ptr<Test1> p1(new Test1());
shared_ptr<Test2> p2(new Test2());
(*p1).p1 = p2;
(*p2).p2 = p1;
cout << p1.use_count() << endl;
cout << p2.use_count() << endl;
if(!(*p1).p1.expired()) //查看是否释放
shared_ptr<Test2> p3 = (*p1).p1.lock();
cout << p1.use_count() << endl;
cout << p2.use_count() << endl;
return 0;
}
结果:这样就可以进行正常释放内存了
总结
如果对您有用,不妨点个赞!谢谢!