<>智能指针

输入问题:
给定一个字符串,不知道有几个字符,怎样输入?
使用cin.getline(); 输入一行。

<>智能指针概念

智能指针主要是针对裸指针进行了一次面向对象的封装,在构造函数中初始化资源地址,在析构函数中释放资源。当资源应该被释放时,指向它的智能指针可以确保自动释放它。

<>RAII

RAII 对堆上空间进行自动化管理——利用对象自动析构的机制。

malloc, new 等动态分配的对象,很有可能忘记了去释放资源而导致泄露。
对于一个对象而言,在构造函数的时候申请空间,而在析构函数(在离开作用域时调用)的时候释放空间,也就是RAII资源获取即初始化技术。

C++11引入智能指针,使用引用计数,让程序员不再需要关心手动释放内存。

<>引用计数

这种计数是为了防止内存泄露而产生的。

对于动态分配的对象,进行引用计数,每当增加一次对同一个对象的引用,那么引用计数就会增加一次,每删除一次引用,引用计数就会减一,当一个对象的引用计数为0时,就会自动删除指向的堆内存。

注意:引用计数不是垃圾回收,引用计数能够尽快收回不再使用的对象,同时在回收过程中也不会造成长时间的等待,更能够清晰的表明资源的生命周期。

<>裸指针
int *ptr;
这种指针被称为裸指针。
使用裸指针会存在一些不足:

*
如果使用裸指针分配内存后,忘记手动释放资源,会出现内存泄漏。

*
如果使用多个裸指针指向同一资源,其中一个指针对资源进行释放,其他指针成为空悬指针,如果再次释放会存在错误。

*
如果程序异常退出时,裸指针的释放资源的代码未能执行,也会造成内存泄漏。

<>智能指针的分类

需要引入头文件#include< memory >智能指针

<>不带引用计数的智能指针auto_ptr

已经废弃

* 不能使用同一个裸指针赋值/初始化多个auto_ptr;
* 拷贝构造和等号运算符—— 将原智能指针置空;
* 不允许隐式构造;
auto_ptr是通过将除最后一个以外的其它auto_ptr 置 nullptr 来避免浅拷贝的发生,它的资源所有权是可以转移的。
void fun() { int* p = new int(10); auto_ptr<int> a_p(p);
//a_p在栈帧上,它会自动析构,会将堆上的p delete //auto_ptr<int> a_p1(p); 崩溃
不能使用同一个裸指针赋值/初始化多个auto_ptr //auto_ptr<int> a_p = p; //拷贝构造 隐式构造,根据类型自推 /*
p生成临时auto_ptr对象——隐式构造 使用临时对象拷贝构造a_p 析构临时对象 ——优化-- 直接构造a_p */ //a_p=a_p2; 等号运算符重载
auto_ptr<int> a_p = auto_ptr<int>(p);//显式构造 cout << *p << endl; cout << *a_p <<
endl; a_p.release();//返回当前指向的地址,并将当前智能指针置空 a_p.reset();//将当前智能指针指向的内存释放,指针置空
a_p.get();//获取智能指针内部指针 }
//auto_ptr a_p = p; 拷贝构造 不允许隐式构造,根据类型自推
*p生成临时auto_ptr对象——隐式构造 * 使用临时对象拷贝构造a_p * 析构临时对象 * ——优化-- 直接构造a_p
auto_ptr a_p = auto_ptr §; 显式构造

<>模拟实现mauto_ptr
#ifndef MAUTO_PTR_H #define MAUTO_PTR_H template<typename T> class Mauto_ptr {
public: explicit Mauto_ptr(T*ptr=nullptr)//explicit防止隐式构造 :_ptr(ptr) {}
Mauto_ptr(Mauto_ptr& src) :_ptr(src.release()) {} Mauto_ptr& operator=(Mauto_ptr
& src)//等号运算符重载 { _ptr = src.release(); } ~Mauto_ptr() { delete_ptr; } T*
release() { T* tmp = _ptr; _ptr = NULL; return tmp; } void reset() { delete_ptr;
_ptr= NULL; } T& operator*()//解引用运算符 { return *_ptr; } T* operator->()
//箭头运算符,是二次调用 { return _ptr; } private: T* _ptr; }; #endif
<>不带引用计数的智能指针unique_ptr

C++ 11

* 不能使用同一个裸指针赋值/初始化多个unique_ptr;
* 不允许隐式构造;
* 不允许拷贝构造,不允许等号运算符重载;
unique_ptr 删除了拷贝构造和赋值函数,因此不支持普通的拷贝或赋值操作。
引入了带有右值引用的拷贝构造和等号运算符重载,可以把 unique_ptr 作为函数的返回值。
//右值引用 用来引用即将死亡的对象——临时对象 unique_ptr<int>fun(unique_ptr<int>& ptr) { cout << *
ptr<< endl; int* p = new int(9); return unique_ptr<int>(p); } void fun() { int*
p= new int(10); unique_ptr<int> u_p; //unique_ptr<int> u_p=p; 不允许隐式构造
//unique_ptr<int> u_p(u_p1);不允许拷贝构造 //u_p1=u_p ;不允许等号运算符重载 unique_ptr<int> u_p(p
); //unique_ptr<int> u_p(new int(10)); cout << *p << endl; cout << *u_p << endl;
u_p.get(); u_p.release(); u_p.reset(); //u_p.swap(); 交换两个智能指针 unique_ptr<int>
u_p2(fun(u_p)); u_p2 = fun(u_p); cout << *u_p2 << endl; }
右值引用 用来引用即将死亡的对象——临时对象
const int& a = 10; int&& b = 10;
<>模拟实现unique_ptr
#ifndef MUNIQUE_PTR_H #define MUNIQUE_PTR_H template<typename T> class
Munique_ptr{ public: explicit Munique_ptr(T* ptr = nullptr) :_ptr(ptr) {}
//Munique_ptr(Munique_ptr& src) = delete; //Munique_ptr& operator=(Munique_ptr&
src) = delete; Munique_ptr(Munique_ptr&& src)//右值引用,引用即将死亡的对象 :_ptr(src.release(
)) { } Munique_ptr& operator=(Mauto_ptr&& src) { _ptr = src.release(); } ~
Munique_ptr() { delete_ptr; } T* release() { T* tmp = _ptr; _ptr = NULL; return
tmp; } void reset() { delete_ptr; _ptr = NULL; } T& operator*() { return *_ptr;
} T* operator->()//箭头运算符,是二次调用 { return _ptr; } operator bool()//bool重载 没有返回值 {
return _ptr != NULL; } private: T* _ptr; }; #endif
<>带引用计数的智能指针shared_ptr——强智能指针

* 不允许隐式构造;
* 不能使用同一个裸指针赋值/初始化多个shared_ptr;
* 允许拷贝构造,允许等号运算符重载;
一个shared_ptr 对资源进行引用时,资源的引用计数会增加一,通常用于管理对象的生命周期。只要有一个指向对象的shared_ptr
存在,该对象就不会析构。
#include<iostream> #include<map> #include<memory>//智能指针 #include"mshared_ptr.h"
using namespace std; template<typename T> map<T*, int> Mshared_ptr<T>::_count =
new map<T*,int>(); void fun() { int* p = new int(11); shared_ptr<int> s_p(p);
shared_ptr<int> s_p1(s_p);//允许拷贝构造 s_p = s_p1;//允许等号运算符重载 cout << s_p.use_count(
) << endl;//引用计数器 cout << *p << endl; cout << *s_p << endl; cout << *s_p1 <<
endl; s_p.unique();//判断当前是否是唯一的 }
<>模拟实现shared_ptr
#ifndef MSHARED_PTR_H #define MSHARED_PTR_H template<typename T> class
Mshared_ptr{ public: explicit Mshared_ptr(T* ptr = nullptr) :_ptr(ptr) {}
Mshared_ptr(Mshared_ptr& src) { /* //返回值为pair 判断插入是否成功 ==1插入成功,==0插入失败 if
(_count.insert(make_pair(_ptr, 2)).second == 0) { _count[_ptr]++; } */ _count.
insert(make_pair(_ptr, 1)); _count[_ptr]++; _ptr = src._ptr; } Mshared_ptr&
operator=(Mshared_ptr&& src) { if (_ptr == src._ptr) { return *this; } if (
unique()) { _count.erase(_ptr); delete _ptr; } else { _count[_ptr]--; } _ptr =
src._ptr; } ~Mshared_ptr() { if (unique()) { _count.erase(_ptr); delete _ptr; }
else { _count[_ptr]--; } _ptr = src._ptr; } bool unique() { if (count.find(_ptr)
== count.end()||count[_ptr]==1)//顺序不能变 { return true; } return false; } T*
release() { T* tmp = _ptr; if (unique()) { _count.erase(_ptr); } else { _count[
_ptr]--; } _ptr = NULL; return tmp; } void reset() { if (unique()) { _count.
erase(_ptr); delete _ptr; } else { _count[_ptr]--; } _ptr = NULL; } T& operator*
() { return *_ptr; } T* operator->()//箭头调用,是二次调用 { return _ptr; } operator bool(
) { return _ptr!=NULL; } private: static map<T*, int>* _count; T* _ptr; };
<>带引用计数的智能指针weak_ptr——弱智能指针

* 不能直接使用,不能解引用;
* 如果要使用必须先转化为强智能指针,用lock()返回强智能指针;
* 弱智能指针不占用引用计数;
* 只能由强智能指针构造弱智能指针;
weak_ptr 对资源的引用不会引起资源的引用计数的变化,通常作为观察者,用于判断资源是否存在,并根据不同情况做出相应的操作。

比如使用 weak_ptr 对资源进行弱引用,当调用 weak_ptr的 lock() 方法时,若返回 nullptr
,则说明资源已经不存在,放弃对资源的继续操作。否则,将返回一个 shared_ptr 对象,可以继续操作资源。

一旦最后一个指向对象的 shared_ptr 被销毁,对象就会被释放。即使有 weak_ptr 指向对象,对象也还是会被释放。

class A { public: A() { cout << "A()" << endl; } ~A() { cout << "~A()" << endl;
} weak_ptr<B> _ptr_b; }; class B { public: B() { cout << "B()" << endl; } ~B() {
cout<< "~B()" << endl; } weak_ptr<A> _ptr_a; }; void fun() { shared_ptr<A> a_p(
newA()); shared_ptr<B> b_p(new B()); shared_ptr<int> p(new int(10));
//强智能指针构造弱智能指针 weak_ptr<int> w_p(p); cout << *p << endl; cout << *(w_p.lock())
<< endl;//lock返回强智能指针 shared_ptr<int> tmp = w_p.lock(); a_p->_ptr_b = b_p;
//无法析构 b_p->_ptr_a = a_p; }
<>模拟实现mweak_ptr
#ifndef MWEAK_PTR_H #define MWEAK_PTR_H #include"mshared_ptr.h" template<
typename T> class Mweak_ptr { public: Mweak_ptr(Mshared_ptr& s_ptr) { _s_ptr =
s_ptr.get(); Mshared_ptr<T>::_count.insert(make_pair(_ptr, 1)); //加友元可以访问 }
Mshared_ptr<T> lock() { if (Mshared_ptr<T>::_count.find(_s_ptr) != Mshared_ptr<T
>::_count.end()) { return Mshared_ptr<T>(_s_ptr); } return Mshared_ptr<T>(); }
private: T* _s_ptr; }; #endif

技术
©2019-2020 Toolsou All rights reserved,
程序员的520,送给女友的几行漂亮的代码(python版)基于stm32控制四轮小车电机驱动(一)linux查看磁盘空间命令实验四 自动化测试工具-软件测试axios拦截器封装与使用C语言——qsort函数opencv-python傅里叶变换以及逆变换在算法研究过程中如何进行算法创新nc的安装和简单操作C语言做一个简易的登陆验证(功能)界面