先说一句为什么要用智能指针。智能指针是为了解决内存泄露的问题。C/C++程序员可以自己开辟堆(heap)上的内存空间,同时也需要自己释放堆上的内存空间。一旦忘记释放内存空间,这样会造成内存泄露。

    不得不提及一下RAII机制(资源获取即初始化,Resource Acquisition Is
Initialization)。在类的构造函数里面申请资源,然后使用,最后在析构函数中释放资源。所以这也就为什么析构函数需要用virtual来修饰来避免出现内存泄露。

    计算机有栈和堆两种。

    这里提及一点。C++中的对象(class)是指所有的内置型对象(int、float、double等和外置型(用户自定义的对象)对象。一切皆为对象。

如果在栈上创建相应的class,那么OS会自动释放掉相应的内存空间,所以RAII机制工作正常,离开相应的作用域时,class会自动调用自己的析构函数释放资源。但是如果采用new方式在堆上创建class,那么class不会调用自己的析构函数。程序员必须使用delete去销毁它。否则就会造成内存泄露。

    这里再插入两个小知识,我以前面试腾讯外包时被问到的点。

*
new、delete的机制。

*
new会抛出异常以及如何让new不抛异常。

    1.new有两个步骤:(1)调用operator new()函数开辟内存空间。(2)调用class的构造函数。

delete也有两个步骤:(1)调用class的析构函数。(2)调用operator delete()释放内存。

    2.new会抛出异常。为了防止抛出异常。就应该使用 std::nothrow。例:

 char *ptr = new(std::nothrow) char [20];

 

    开始介绍智能指针,他们都包含在头文件#include <memory>中。主要解决了部分获取资源自动释放的问题。

*
unique_ptr 

    独占式智能指针,不允许拷贝复制,不允许拷贝构造。它不仅能代理new创建的单个对象,也能够代理new[]创建的对象数组。

    代码如下:
/// /// @file unique.cpp /// @author kogan(709954896@qq.com) /// @date
2020-06-21 09:28:02 /// #include <iostream> #include <memory> #include
<utility> using std::cout; using std::endl; int main() {
//make_unique在C++11中被遗漏了,在C++14中添加。所以要使用-std=c++14 //创建int型指针。 //使用工厂方法创建
std::unique_ptr<int> ptr = std::make_unique<int>(5); //也可以初始化时直接创建
std::unique_ptr<int> ptr2(new int(6)); //std::unique_ptr<int> ptr3(ptr);
//不允许拷贝构造 //std::unique_ptr<int> ptr3 = ptr;//不允许赋值 //创建int型动态数组
std::unique_ptr<int[]> ptrArray = std::make_unique<int[]>(20); cout << "*ptr: "
<< *ptr << endl; //创建出来的unique动态数组,可以使用下表访问。 ptrArray[2] = 3; cout <<
ptrArray[2] << endl; //错误用法,能编译成功,但是会出问题。 //std::unique_ptr<int> ptr5(new
int[20]); return 0; }
*
shared_ptr

    引用计数型智能指针。是最有价值、最重要、最有用的组成部分。可以自由地拷贝和赋值。当这个指针指向某个指针时,会引用计数加一。如果是从另外一个smart_ptr那里获取某指针的管理权,则两个smart_ptr指针都会引用计数加一。当引用计数为0时,smart_ptr会删除指针所指向的内存空间。

    代码如下:
/// /// @file shared.cpp /// @author kogan(709954896@qq.com) /// @date
2020-06-21 11:51:39 /// #include <iostream> #include <memory> using std::cout;
using std::endl; int main() { //初始化方式 std::shared_ptr<int> ptr(new int(3));
std::shared_ptr<int> ptr2 = std::make_shared<int>(5); //将ptr2管理的指针赋值给ptr3
std::shared_ptr<int> ptr3(ptr2); cout << ptr3.use_count() << endl; return 0; }
面试重点:循环引用计数。

循环引用计数:两个smart_ptr指针互相指向对方,造成内存泄露。此时需要使用weak_ptr。

    代码如下:

*
weak_ptr

弱引用指针。用于观察shared_ptr或weak_ptr。用于解决循环引用计数。因为weak_ptr没有共享资源,它的构造函数不会引起指针引用计数的变化。

 
/// /// @file circle_reference.cpp /// @author kogan(709954896@qq.com) ///
@date 2020-06-21 12:04:48 /// #include <iostream> #include <memory> using
std::cout; using std::endl; using std::shared_ptr; class Child;//前置声明 class
Parent { public: Parent(){ cout << "Parent()" << endl; } ~Parent() { cout <<
"~Parent()" << endl; } shared_ptr<Child> m_Child; }; class Child { public:
Child(){ cout << "Child()" << endl; } ~Child(){ cout << "~Child()" << endl; }
shared_ptr<Parent> m_Parent; }; int main(void) { //shared_ptr的循环引用会导致内存泄漏
shared_ptr<Parent> parent(new Parent); shared_ptr<Child> child(new Child); cout
<< "sizeof(shared_ptr) = " << sizeof(parent) << endl; cout << "parent 's
use_count() = " << parent.use_count() << endl; cout << "child's use_count() = "
<< child.use_count() << endl; parent->m_Child = child;//赋值 child->m_Parent =
parent; cout << "parent 's use_count() = " << parent.use_count() << endl; cout
<< "child's use_count() = " << child.use_count() << endl; return 0; }
使用weak_ptr后不会发生内存泄露。

 
/// /// @file circle_reference2.cpp /// @author kogan(709954896@qq.com) ///
@date 2020-06-21 12:09:37 /// #include <iostream> #include <memory> using
std::cout; using std::endl; using std::shared_ptr; using std::weak_ptr; class
Child;//前置声明 class Parent { public: Parent(){ cout << "Parent()" << endl; }
~Parent() { cout << "~Parent()" << endl; } shared_ptr<Child> m_Child; }; class
Child { public: Child(){ cout << "Child()" << endl; } ~Child(){ cout <<
"~Child()" << endl; } //shared_ptr<Parent> m_Parent; weak_ptr<Parent> m_Parent;
}; int main(void) { //shared_ptr的循环引用会导致内存泄漏 // //解决方案是将其中一个指针设置为weak_ptr
//weak_ptr做赋值操作的时候,不会改变引用计数的值 shared_ptr<Parent> parent(new Parent);
shared_ptr<Child> child(new Child); cout << "sizeof(shared_ptr) = " <<
sizeof(parent) << endl; cout << "parent 's use_count() = " <<
parent.use_count() << endl; cout << "child's use_count() = " <<
child.use_count() << endl; parent->m_Child = child;//赋值 child->m_Parent =
parent;// weak_ptr = shared_ptr; cout << endl << "执行赋值之后:" << endl; cout <<
"parent 's use_count() = " << parent.use_count() << endl; cout << "child's
use_count() = " << child.use_count() << endl; return 0; }
 另一种循环引用计数:
closs node { public: typedef shared_ptr<Node> ptr_type; ptr_type next; };
auto p1 = make_shared_ptr<Node>(); auto p2 = make_shared_ptr<Node>();
weak的lock函数,在某个作用于内使用lock()会返回一个shared_ptr。

该对象可以操作weak_ptr所指向的shared_ptr。

 
/// /// @file shared.cpp /// @author kogan(709954896@qq.com) /// @date
2020-06-21 11:51:39 /// #include <iostream> #include <memory> using std::cout;
using std::endl; int main() { //初始化方式 std::shared_ptr<int> ptr(new int(3));
std::shared_ptr<int> ptr2 = std::make_shared<int>(5); //将ptr2管理的指针赋值给ptr3
std::shared_ptr<int> ptr3(ptr2); cout << "reference count: " <<
ptr3.use_count() << endl; std::weak_ptr<int> wptr(ptr); cout << "reference
count: " << ptr3.use_count() << endl; { cout << "*ptr: " << *ptr << endl;
std::weak_ptr<int> wptr(ptr); auto sp = wptr.lock(); (*sp) = 5; cout << "*ptr:
" << *ptr << endl; } cout << "*ptr: " << *ptr << endl; return 0; }
 

技术
©2019-2020 Toolsou All rights reserved,
继承jpa Repository 写自定义方法查询Spark SQL-编程 云计算的最大安全风险:安全责任不清Vue 中获取下拉框的文本及选项值Dijkstra算法的Python实现-最短路径问题[work] python读取txt文件最后一行Three.js - OrbitControls 轨道控件的围绕目标 target 参数【JAVA】【华为校园招聘笔试-软件】2020-09-09(精华)2020年7月15日 微信小程序 组件Component的使用airflow 定时任务+时间设定+cron表达式