一、基础概念
1.内存泄漏:内存泄漏是指程序中已动态分配的堆内存由于某种原因因程序未释放或无法释放,导致程序运行速度减慢甚至系统崩溃等。
内存泄漏两种情况:
- 堆内存泄漏:在堆上申请了资源,结束时,没有还给OS。
- 资源泄漏:指系统资源,比如socket,文件描述符,因为有限制。创建而不归还,资源就会耗尽。
2.什么是智能指针
由于c++语言没有垃圾回收机制,必须自己去释放动态分配的堆内存,否则就回内存泄漏,解决这个问题就是使用智能指针。
在智能指针对象中有一个指针,此指针存储的是动态创建对象的地址,用于生存期的控制,能够确保智能指针对象离开所在作用域是,自动正确的销毁动态创建的对象
3.RALL
资源获取即初始化,充分利用了c++语言局部对象自动销毁的特性来控制生命周期。
RALL过程总结:
1.设计一个类封装资源
2.在构造函数中初始化
3.在析构函数中进行销毁操作
4.使用时定义一个该类的局部对象
using namespace std;
class Int
{
private:
int a = 10;
public:
Int(int b=0):a(b){}
~Int(){}
};
class Ptr
{
private:
Int* p;
public:
Ptr(Int* s) :p(s) {}
~Ptr()
{
delete p;
}
};
int main()
{
Ptr ptr(new Int(10));//调动构造函数创建对象,将堆区中对象地址给ptr
}
4.裸指针存在问题
- 难以区分指针指向的是单个对象还是一组对象
- 使用完指针之后无法判断是否应该销毁指针,因为无法判断指针是否“拥有”指向的对象
- 无法确定使用delete关键字删除,还是其他特殊的销毁机制
- 无法判断当前指针是否是空悬指针
5.auto_ptr的剖析
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
using namespace std;
namespace xw
{
template<class _Ty>
class My_auto_ptr
{
public:
typedef _Ty element_type;
private:
_Ty* _M_ptr;
public:
explicit My_auto_ptr(_Ty* p = nullptr) :_M_ptr(p) {}
~My_auto_ptr() { delete _M_ptr; }
_Ty* get()const { return _M_ptr; } //前面是否加const看_M_ptr所指之物(*_M_ptr)是否允许改变
};
}
//值语义
class Int
{
private:
int value = 10;
public:
Int(int b = 0) :value(b) { cout << "create Int" << endl; }
~Int() { cout << "Destory Int" << endl; }
int& Value() { return value; }
const int& Value()const { return value; }
void PrintInt(){cout<<value<<endl;}
};
int fun(int i)
{
xw::My_auto_ptr<Int>sp(new Int(10));
if (i < 0)
{
throw std::out_of_range("i<0");
}
return i;
}
int main()
{
int x = 0;
try
{
x = fun(-10);
}
catch (std::out_of_range& e)
{
cout << e.what() << endl;
}
}
6.auto_ptr辅助函数的实现
- get返回指向被管理对象的指针
- 重载 operator* (取值),operator->(成员访问),访问被管理对象
_Ty& operator*()const
{
return *_M_ptr;
}
_Ty* operator->()const
{
return _M_ptr;
}
int main()
{
xw::My_auto_ptr<Int>sp(new Int(10));
sp->PrintInt();
(*sp).Value()=100; //.的优先级高于*
sp.operator->()->PrintInt();
}
7.auto_ptr辅助函数的实现2
- reset替换被管理对象
- release释放被管理对象的所有权
void reset(_Ty *p=nullptr)
{
delete _M_ptr;
_M_ptr=p;
}
_Ty* relese()
{
_Ty* temp=_M_ptr;
_M_ptr=nullptr;
return temp;
}
void Swap(My_auto_ptr&_Other)
{
std::swap(this->_M_ptr,_Other._M_ptr);
}
int main()
{
xw::My_auto_ptr<Int>sp(new Int(10));
sp->PrintInt();
sp.reset(new Int(20));
sp->PrintInt();
Int* p=sp.release();
sp->PrintInt();//程序运行出错,此时给nullptr解引用了
}
//关于交换
int main()
{
xw::My_auto_ptr<Int>sp(new Int(10));
sp->PrintInt();
xw::My_auto_ptr<Int>p2; //p2._M_ptr=nullptr;
p2.Swap(sp);
sp->PrintInt();//error
}
8.auto_ptr的拷贝构造函数的问题
My_auto_ptr(const My_auto_ptr& _other)
{
//_M_ptr=_other._M-ptr;//浅拷贝 析构两次,产生失效指针,程序崩溃
_M_ptr=new _Ty(*other);
}
//对象语义指的是面向对象意义下的对象,对象拷贝是禁止的
例如:文件的拷贝,即使是深拷贝,但是他们依然在同一个文件里面“a.txt”文章来源:https://www.toymoban.com/news/detail-429415.html
void func()
{
xw::My_auto_ptr<Int>(new Int[10]);//调用了10次构造函数
return
}
auto_ptr三大问题:文章来源地址https://www.toymoban.com/news/detail-429415.html
- 赋值和复制会改变资源所有权,不符合人的直觉
- 在STL容器中使用auto_ptr存在重大风险,因为容器内的元素必须支持可复制的可赋值(因为拷贝构造和赋值语句中没有const 修饰了,容易发生资源转移)
- 不支持对象数组的操作
C++11中已经舍弃auto_ptr
到了这里,关于c++11智能指针之基础概念的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!