C++常用类 shared_ptr

原创 2015年07月08日 21:18:04

unCopyable类

class unCopyable{
protected:
unCopyable(){}
~unCopyable(){}
private:
 unCopyable(const unCopyable &);
unCopyable & operator=(const unCopyable&);
}
class home :private unCopyable{}

注意上面的基类的protected类型的构造函数和析构函数,子类是private继承。private继承是实现继承。

赋值操作符:

widget & widget::operator=(const  widget& rh){

 if(this == &rh)

return *this;

delete pb;

pb = new Bitmap(*rh.pb);

reruen *this;

}

这种函数虽然考虑了两者相同的情况,但是没有考虑当new操作发生异常时 的情况。当异常是,pb会指向已经释放的内存,导致不确定行为。

更好的方式是

widget & widget::operator=(const  widget& rh){

Bitmap* porig = pb;

pb = new Bitmao(*rh.pb);

delete porig;

return *this;

}

这里即使两者相同,也不会有问题,只不过多做了一次拷贝,对效率有影响。我们可以考虑将判断语句加进去,但是判断语句会使代码变大,产生新的分支流,这两点都会降低CPU的效率。所以我们应该考虑自我赋值的发生频率有多高。

还有一个替代方案是copyandswap技术:

class widget{

private:

void swap(const widget&rh){}

public:

widget & widget::operator=(const  widget& rh){

widget temp (rh);

swap(temp);

return *this;

}

C++定义隐式转换函数

  C++中单参数构造函数若不声明为explict,在合适的场合可以产生隐式转换:由成员变量类型转换为类类型。

  下面的代码展示如何实现反向的转换: 

void changeFontSize(FontHandle f, int newsize);
class Font{
public:
    operator FontHandle() const   //隐式转换函数
    {
        return f;
    }
private:
    FontHandle f;
};

Font f;
int newsize;
changeFontSize(f, newsize);      //将Font隐式转换成FontHandle


 

   另外,两个或更多参数的non-explicit构造函数,如果所有形参都提供了默认实参,那么在需要一个类类型对象的表达式位置,提供一个first形参类型的对象,编译器也执行隐式转换,转换得到一个类对象。

  如,构造函数Rational(int num1 = 0,  int num2 = 1); Rational类中重载了operator*。表达式result = oneHalf * 2; 2发生隐式转换为Rational对象。result 和 onehalf为Rational对象。


隐式转换函数:

class Font{

private: 

FontHandle f;

public :

operator FontHandle() const{//隐式转换

return f;

}

}

void changeFrontSize(FontHandle f ,int size){}

Font font;

int size;

当以Font对象调用changeFrontSize函数时,便会执行隐式转换函数,这样

changeFrontSize(font,size);

用对象管理资源的原因:

因为异常会导致函数未执行完提前返回,所以我们正常的在函数末尾释放资源会因为异常的发生造成内存泄露。所以要才有对象管理资源,当对象离开作用域时,会自动执行其析构函数,这样就会保证资源的释放。

ecplicit关键字

隐式转换可以用explict关键字防止。其主要是防止一个类型的对象转换出另一个新的类型的新对象。

默认构造函数是用于构造对象的,这两个没什么太大关系,将默认构造函数声明为explicit可以防止参数类型对象生成一个类类型的临时对象。


关于C++的shared_ptr,只有在其通过复制构造函数和赋值操作符时,两者的引用计数才和对象持有者相关。从以下两个例子可以看出来:

# include <iostream>
# include <tr1/memory>
using namespace std;
class A {
public:
    A() {
        cout << "construct A!!!" << endl;
    }
    ;
    ~A() {
        cout << "destruct A!!!" << endl;
    }
    ;
};
class B: public A {
public:
    B() {
        cout << "construct B!!!" << endl;
    }
    ;
    ~B() {
        cout << "destruct B!!!" << endl;
    }
    ;
};
int main() {
//  B* ptrB0 = new B();
    B * pint = new B();
    std::tr1::shared_ptr<B> ptrB1(pint);

    std::tr1::shared_ptr<B> ptrB2(ptrB1);

    std::tr1::shared_ptr<B> ptrB3(ptrB1);
    cout << ptrB1.use_count() << endl;
    cout << ptrB2.use_count() << endl;
    cout << ptrB3.use_count() << endl;
}

这个打印出的结果是3

# include <iostream>
# include <tr1/memory>
using namespace std;
class A {
public:
    A() {
        cout << "construct A!!!" << endl;
    }
    ;
    ~A() {
        cout << "destruct A!!!" << endl;
    }
    ;
};
class B: public A {
public:
    B() {
        cout << "construct B!!!" << endl;
    }
    ;
    ~B() {
        cout << "destruct B!!!" << endl;
    }
    ;
};
int main() {
//  B* ptrB0 = new B();
    B * pint = new B();
    std::tr1::shared_ptr<B> ptrB1(pint);

    std::tr1::shared_ptr<B> ptrB2(pint);

    std::tr1::shared_ptr<B> ptrB3(pint);
    cout << ptrB1.use_count() << endl;
    cout << ptrB2.use_count() << endl;
    cout << ptrB3.use_count() << endl;
}

这个的打印结果是1.

这也就说明引用计数和所对应的对象不是强相关的,自我理解应该是这样,当shared_ptr初始化时(通过非同类对象),会申请一块内存进行引用计数。当通过同类对象进行初始化时,就会使用同一块内存,而不是新申请。也就是只有通过赋值操作符和复制构造函数才会使引用计数有效。

定义类时应该考虑的问题:

如果只是想简单的添加机能,首先要考虑是否只定义一个nonmember函数或templates就可以了。
定义一整个class家族的话,就应该定义class template。

对象切割问题:

子类对象以by value传递,并被视为一个基类对象,会导致基类的复制构造函数被调用,而造成此对象的行为像个derived对象的特化性质全部被切掉,仅留下base class 对象

pass by value和pass by const reference

内置类型和stl的迭代器和函数对象都适合传value。这样效率更高。之所以用reference,主要是因为reference高效且能避免切割问题。

non local static 对象的交互问题

当不同文件的nonlocal static对象之间存在依赖关系时,我们可以吧其转换为local static对象,通过在函数中定义static对象,并返回其引用,这样就可以保证在别的对象获取到这个对象时,其已经时初始化过的。
但不论是local还是non local,在多线程下等待某事发生都会有麻烦,处理这种麻烦的一种做法是,在单线程启动阶段手工调用所有reference return函数,这样就可以消除与初始化有关的”竞速形式“。

对封装而言只有private(封装)和其他(不封装)两种访问权限。protected并不比public更具有封装性。


shared_ptr智能指针模板类的简单实现(c++11)

前言 最近突然萌生把stl常用的库都通通自己过一遍的想法,算是对泛型编程的一次学习,也深入理解stl,还是对c++11知识的练习,就从智能指针开始吧。 另外,c++11让c++程序变得简洁优...
  • to_be_better
  • to_be_better
  • 2016年12月11日 04:51
  • 877

std::shared_ptr 和 std::weak_ptr的用法以及引用计数的循环引用问题

在std::shared_ptr被引入之前,C++标准库中实现的用于管理资源的智能指针只有std::auto_ptr一个而已。 std::auto_ptr的作用非常有限,因为它存在被管理资源的所有权...
  • fireroll
  • fireroll
  • 2015年12月17日 14:43
  • 513

C++智能指针shared_ptr的三种使用方式

智能指针通常是指基于引用计数的智能指针,在c++11标准中就是std::shared_ptr。它的特点是如果可以安全的放入STL容器中。 有以下三种方式可以使用shared_ptr 1. 如果你的...
  • fanyun_01
  • fanyun_01
  • 2017年03月31日 12:39
  • 1199

C++11中使用shared_ptr和unique_ptr管理动态数组

在C++11中,若使用shared_ptr管理一个动态数组,则需手动制定一个删除器。 auto sp = std::shared_ptr(new int[len], [](char *p){delet...
  • wks19891215
  • wks19891215
  • 2016年03月27日 16:13
  • 4740

C++ - "shared_ptr"的使用方法 及 代码

"shared_ptr"的使用方法 及 代码   智能指针(smart pointer)是C++11的新特性. 指针在无人使用时, 自动释放动态内存. 通过"use_count"计数, 并判断是否无人...
  • u012515223
  • u012515223
  • 2013年11月04日 09:45
  • 2819

我所熟悉的C++智能指针auto_ptr vs shared_ptr (一)

在开发过程中,曾经使用过两种C++的智能指针,如今,便总结一下,顺便比较比较二者使用中的区别,注意避免入坑的危险。:-D 我们知道,在C++中,如果创建一个指向某个对象的指针,那么在使用完这个对象...
  • u013700658
  • u013700658
  • 2015年10月28日 09:24
  • 1460

c++智能指针的使用,auto_ptr,shared_ptr

今天写程序时想用智能指针与vector容器一起解决指针数组的成员管理问题。在我的程序中我用到了多个指针容器,这样就导致了一个问题,这些指针容器的清空非常繁琐,我不能仅仅调用一次clear就能完成,我需...
  • liushu1231
  • liushu1231
  • 2013年04月08日 20:23
  • 2241

从零开始学C++之boost库(一):详解 boost 库智能指针(scoped_ptr<T> 、shared_ptr<T> 、weak_ptr<T> 源码分析)

一、boost 智能指针 智能指针是利用RAII(Resource Acquisition Is Initialization:资源获取即初始化)来管理资源。关于RAII的讨论可以参考前面的文 章。在...
  • Simba888888
  • Simba888888
  • 2013年07月29日 17:15
  • 12319

【C++11新特性】 C++11智能指针之shared_ptr

C++中的智能指针首先出现在“准”标准库boost中。随着使用的人越来越多,为了让开发人员更方便、更安全的使用动态内存,C++11也引入了智能指针来管理动态对象。在新标准中,主要提供了shared_p...
  • Xiejingfa
  • Xiejingfa
  • 2016年02月26日 15:21
  • 13753

c++11 条款19:使用std::shared_ptr来进行共享所有权的资源管理

条款19:使用std::shared_ptr来进行共享所有权的资源管理 使用垃圾回收的程序员会嘲笑c++程序员阻止资源泄漏的方法,“好原始啊!”他们嘲笑。“你们没有在1960年代从Lisp里获取备忘录...
  • coolmeme
  • coolmeme
  • 2015年01月28日 17:27
  • 8760
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:C++常用类 shared_ptr
举报原因:
原因补充:

(最多只允许输入30个字)