智能指针:
    为什么需要智能指针?
        1. malloc出来的空间,没有进行释放,存在内存泄漏的问题。 
        2. 异常安全问题。如果在malloc和free之间如果存在抛异常,那么还是有内存泄漏。这种问题就叫异常安 全。
    RAII:
        是一种利用对象生命周期来控制程序资源(如内存,文件句柄,网络连接,互斥俩个等等)的简单技术
        优点:
            1.不需要显示地释放资源
            2.采用这种方式,对象所需地资源在其生命周期内始终保持有效

// 使用RAII思想设计的SmartPtr类
template<class T>
class SmartPtr {
public:
SmartPtr(T* ptr = nullptr)
: _ptr(ptr)
{} ~SmartPtr() {
if(_ptr)
delete _ptr;
}
private:
T* _ptr;
}; void MergeSort(int* a, int n) {
int* tmp = (int*)malloc(sizeof(int)*n);
// 讲tmp指针委托给了sp对象,用时老师的话说给tmp指针找了一个可怕的女朋友!天天管着你,直到你go die^^
SmartPtr<int> sp(tmp);
// _MergeSort(a, 0, n - 1, tmp);
// 这里假设处理了一些其他逻辑
vector<int> v(, );
// ...
} int main() {
try {
int a[] = { , , , , };
MergeSort(a, );
}
catch(const exception& e) {
cout<<e.what()<<endl;
}
return ;
}
    智能指针原理:
        需要具备指针地行为,可以解引用,也可以通过->去访问所指空间中地内容,因此还需要将*, ->,重载

template<class T>
class SmartPtr {
public:
SmartPtr(T* ptr = nullptr)
: _ptr(ptr)
{}
~SmartPtr() {
if(_ptr)
delete _ptr;
}
T& operator*() {return *_ptr;}
T* operator->() {return _ptr;}
private
T* _ptr;
};
struct Date {
int _year;
int _month;
int _day;
};
int main() {
SmartPtr<int> sp1(new int);
*sp1 =
cout<<*sp1<<endl; SmartPtr<int> sparray(new Date);
// 需要注意的是这里应该是sparray.operator->()->_year = 2018;
// 本来应该是sparray->->_year这里语法上为了可读性,省略了一个->
sparray->_year = ;
sparray->_month = ;
sparray->_day = ;
}
总结智能指针的原理:
    1.RAII特性
    2.重载opreator* 和operator->,具有像指针一样的行为
 
C++11和boost中智能指针的关系
  1. C++98中产生了第一个智能指针auto_ptr
  2. C++boost给出了更实用的scoped_ptr和shared_ptr和weak_ptr
  3. C++11,引入了unique_ptr和share_ptr和weak_ptr.需要注意的是unique_ptr对应boost的scoped_ptr.并且这些智能指针是实现原理是参考boost中的实现的
auto_ptr {

构造->保存指针信息
析构->释放指针空间 auto_ptr<int> ptr(ptr2);
拷贝构造->(转移管理权的形式,将ptr2赋值给_ptr,置空ptr2) auto_ptr<int> ptr = ptr2;
赋值运算符重载->(转移管理权,判断是否自己给自己赋值,先释放自己所指向的空间,在用ptr2赋值给_ptr,置空ptr2) }
unique_ptr {
//线程安全 //不支持拷贝构造
C++:
unique_ptr(const unique+ptr<T>& ap) = delete;
unique_ptr<T>& opreator=(const unique_ptr<T>& ap) = delete; C++:
//只声明,不实现,声明成私有 }
shared_ptr {
//会存在引用计数的线程安全问题 //实现了引用计数的方式 ////////////////////////////////////////////////////////////////////////////////////
//此方法存在一定问题
private:
T* _ptr
statice int _count;
//使用statice会存在一定问题:
//使用了statice后每个对象只会公用一块空间,而当需要多块空间来计数的时候就不能实现
//sp1; sp2(sp1)-> 1和2公用一个空间 sp3; sp4(sp3);->3和4公用一块空间
//这样就需要两个引用计数,但是statice后一个类只能存在一个引用计数
//////////////////////////////////////////////////////////////////////////////////// public:
shared_ptr(T* ptr)
:_ptr(ptr)
,_pcount(new int())
{} shared_ptr(const shared_ptr<T>& sp)
:_ptr(sp._ptr)
,_pcount(sp._pcount)
{
(*_pcount)++;
} shared_ptr<T>& operator=(const shared_ptr<T>& sp)
{
if(this != &sp)
{
//ptr1; ptr2(ptr1)
//ptr3; ptr3 = ptr2;
//先判断ptr2的计数是否为0,不为0则不能释放,说明其他指针还在使用
if(--(*_pcount) == )
{
delete _pcount;
delete _ptr;
}
_ptr = sp._ptr;
_pcount = sp._pcount;
(*_pcount)++;
}
return *this;
} ~shared_ptr()
{
if(--(*_pcount) == )
{
delete _ptr;
delete _pcount;
_pcount = nullptr;
_ptr = nullptr;
}
} private:
T* _ptr;
int* _pcount;
//_pcount 在堆上,会存在线程安全问题
}
//shared_ptr 修改确保shared_ptr的线程安全问题

shared_ptr {

public:
shared_ptr(T* ptr)
:_ptr(ptr)
,_pcount(new int())
{} shared_ptr(const shared_ptr<T>& sp)
:_ptr(sp._ptr)
,_pcount(sp._pcount)
{
(*_pcount)++;
} shared_ptr<T>& operator=(const shared_ptr<T>& sp)
{
if(this != &sp)
{
//ptr1; ptr2(ptr1)
//ptr3; ptr3 = ptr2;
//先判断ptr2的计数是否为0,不为0则不能释放,说明其他指针还是只用
if(--(*_pcount) == )
{
delete _pcount;
delete _ptr;
}
_ptr = sp._ptr;
_pcount = sp._pcount;
(*_pcount)++;
}
return *this;
} ~shared_ptr()
{
if(--(*_pcount) == )
{
delete _ptr;
delete _pcount;
_pcount = nullptr;
_ptr = nullptr;
}
} private:
T* _ptr;
int* _pcount;
//_pcount 在堆上,会存在线程安全问题
} struct Date{
int _year;
int _month;
int _day;
};
shared_ptr 的循环引用问题:
    在链表的情况:
struct ListNode{
//ListNode* _next;
//ListNode* _prev;
/*
std::shared_ptr<ListNode> _next;
std::shared_ptr<ListNode> _prev;
*/ std::weak_ptr<ListNode> _next;
std::weak_ptr<ListNode> _prev; ~ListNode()
{
cout << "~ListNode()" << endl;
}
}; int main()
{
std::shared_ptr<ListNode> node1(new ListNode);
std::shared_ptr<ListNode> node2(new ListNode);
cout << node1.use_count() << endl;
cout << node2.use_count() << endl; node1->_next = node2;
node2->_prev = node1; cout << node1.use_count() << endl;
cout << node2.use_count() << endl; return ;
}
        week_ptr——>为了解决shared_ptr产生的循环引用,它并不是RAII思想
            特点:
                1.不会增加引用计数
                2.只可以接收shared_ptr赋值给它
                3.本质并不是一个智能指针

C++新特性---智能指针的更多相关文章

  1. [C++11新特性] 智能指针详解

    动态内存的使用很容易出问题,因为确保在正确的时间释放内存是极为困难的.有时我们会忘记释放内存产生内存泄漏,有时提前释放了内存,再使用指针去引用内存就会报错. 为了更容易(同时也更安全)地使用动态内存, ...

  2. c++11新特性实战(二):智能指针

    c++11添加了新的智能指针,unique_ptr.shared_ptr和weak_ptr,同时也将auto_ptr置为废弃(deprecated). 但是在实际的使用过程中,很多人都会有这样的问题: ...

  3. C++ template的一些高级用法(元编码,可变参数,仿函数,using使用方法,. C++ 智能指针)

    1 .  通用函数可变参数模板 对于有些时候,我们无法确切的知道,函数的参数个数时,而又不想过多的使用所谓的函数重载,那么就可以效仿下面的例子: #include<iostream> #i ...

  4. [转]C++智能指针的创建

    zero 坐在餐桌前,机械的重复“夹菜 -> 咀嚼 -> 吞咽”的动作序列,脸上用无形的大字写着:我心不在焉.在他的对面坐着 Solmyr ,慢条斯理的吃着他那份午餐,维持着他一贯很有修养 ...

  5. c++ 智能指针【转载】

    zero 坐在餐桌前,机械的重复“夹菜 -> 咀嚼 -> 吞咽”的动作序列,脸上用无形的大字写着:我心不在焉.在他的对面坐着 Solmyr ,慢条斯理的吃着他那份午餐,维持着他一贯很有修养 ...

  6. 智能指针--C++

    智能指针(一):STL auto_ptr实现原理 智能指针实际上是一个类(class),里面封装了一个指针.它的用处是啥呢? 指针与内存 说到指针自然涉及到内存.我们如果是在堆栈(stack)中分配了 ...

  7. 转:c++ 11 新特性

    声 明:本文源自 Danny Kalev 在 2011 年 6 月 21 日发表的<The Biggest Changes in C++11(and Why You Should Care)&g ...

  8. C++ | 智能指针初探

    智能指针初探 在 c/c++ 语言中有一种特殊的类型--指针类型. 指针作为实体,是一个用来保存一个内存地址的计算机语言中的变量.它可以直接对内存地址中的数据进行操作,是一种非常灵活的变量.指针被誉为 ...

  9. C++11 智能指针

    C++ 11标准库引入了几种智能指针 unique_ptr shared_ptr weak_ptr C++内存管理机制是当一个变量或对象从作用域过期的时候就会从内存中将他干掉.但是如果变量只是一个指针 ...

随机推荐

  1. Postgresql修改字段的长度

    alter table tbl_exam alter column question type character varing(1000); alter table tbl_exam alter c ...

  2. BitmapFactory: inSampleSize 的一些思考

    一. BitmapFactory.Options 中inSampleSize的取值问题 关于inSampleSize的取值问题Google已经给出了一个推荐的算法:(https://developer ...

  3. 放射渐变RadialGradient

    public RadialGradient(float centerX, float centerY, float radius, int[] colors, float[] stops, TileM ...

  4. MySQL数据类型(最大值 和 最小值)

    MySQL数据类型(最大值 和 最小值) 1.整型 MySQL数据类型 含义(有符号) tinyint(m) 1个字节  范围(-128~127) smallint(m) 2个字节  范围(-3276 ...

  5. 让群辉支持DTS音轨

    让群晖Video Station支持DTS音轨的方法原因:因版权问题,群晖Video Station默认不支持DTS音轨,因此默认不能播放使用DTS音轨的影片. 网上搜到好多解决办法,通常是让添加源h ...

  6. OpenStack社区中的GO语言之争

    1 背景介绍 Swift之前几乎所有的代码都是用Python实现的,但是性能一直不理想, 社区为了解决性能问题,尝试过很多方法,后来发现用Golang语言进行一部分代码重写, 性能得到了一定的提升,社 ...

  7. matlab学习——04图与网络(最短路,最小生成树,最大流)

    04图与网络 1.最短路 (1) 自己写的dijstra算法 format compact; clc,clear all a=zeros(6); a(1,2)=50;a(1,4)=40;a(1,5)= ...

  8. Object.defineProperty()方法学习笔记

    这是js中一个非常重要的方法,ES6中某些方法的实现依赖于它,VUE通过它实现双向绑定 此方法会直接在一个对象上定义一个新属性,或者修改一个已经存在的属性, 并返回这个对象 参数 Object.def ...

  9. 搭建sqli靶场

    前言: sqli是一个印度程序员编写的,用来学习sql注入的一个游戏教程 sqli这个靶场对php7.0是不兼容的(因为一些函数在php7中被删除了),所以搭建的时候要下载php5,如果你的系统要下载 ...

  10. boost::bind四种应用场景的例子

        普通函数 int f( int a, int b ){return a + b;}boost::bind( f, _1, 9 )( 1 ) 成员函数 struct demo{int f( in ...