scoped_ptr analysis

来源:互联网 发布:证件照扫描软件 编辑:程序博客网 时间:2024/05/02 01:53
/*一、概述:1.1宏MOVE_ONLY_TYPE_FOR_CPP_03是针对c++03实现move语义用的。在c++11中已经实现了T&& var的rvalue,而为了兼容老编译器,没有用新语法。所以,需要手动实现move语义。不过,这个宏所提供的机制在新的c++中照样能工作。(好像效率没有rvalue高,会生出一些临时变量)1.2将拷贝构造函数type(type&);和赋值运算符都设置成私有,防止拷贝发生。因为在语义上,本指针是个作用域指针,一般声明在栈上。假设有p1,p2; p1内含有对象obj,如果copy语义发生的话 p2(p1);或 p2=p1;那么p1,p2同时含有obj对象指针,若二者其中一个先出了作用域,那么它会把obj释放掉,导致另一个指针对象非法。1.3同时,拷贝构造函数三种情况:a. 作为函数返回值b. 作为函数参数c. 用一个对象构造另一个同类对象在这些时刻,拷贝构造函数会被隐式地调用,会造成麻烦,所以拷贝构造函数被私有。而赋值operator用起来会让人误以为两个指针都有obj对象地址,给程序员造成不便(不直观嘛),所以也给它私有了。1.4私有了以后,因为永远不会被调用,则也没有具体的实现。1.5scoped_ptr是有作用域的对象,出了作用域,它就会析构,进而删除体内new出来的对象。那么scoped_ptr不能是new出来的,否则需要有人显式地delete它。二、源代码:对源代码进行了改变,把那个展开到scoped_ptr中去了,并且添加了打印信息,方便分析。*/    template <class C>class scoped_ptr {// MOVE_ONLY_TYPE_FOR_CPP_03(scoped_ptr, RValue)private:  struct RValue : public scoped_ptr { RValue(){cout<<"rvalue_type()"<<this<<endl;} ~RValue(){cout<<"~rvalue_type()"<<this<<endl;} RValue(const RValue&){cout<<"rvalue_type(const rvalue_type&)"<<this<<endl;} void operator=(const RValue&){cout<<"void operator=(const rvalue_type&)"<<this<<endl;} }; scoped_ptr(scoped_ptr&); void operator=(scoped_ptr&); public: operator RValue&(){cout<<"=======operator rvalue_type&() of ["<<this<<"]"<<endl; return *reinterpret_cast<RValue*>(this); } scoped_ptr Pass(){cout<<"in the Pass() of ["<<this<<"]"<<endl;return scoped_ptr(*reinterpret_cast<RValue*>(this)); }private:public: typedef C element_type; explicit scoped_ptr(C* p = NULL) : ptr_(p) {cout<<"explicit scoped_ptr(C* p ="<< p<<") : ptr_(p) current:["<<this<<"]"<<endl; }template <typename U>scoped_ptr(scoped_ptr<U> other){cout<<"scoped_ptr(scoped_ptr<U> other="<<&other<<"):ptr_(other.release())current:["<<this<<"]"<<endl;ptr_=(other.release());}  scoped_ptr(RValue& other)   {cout<<" scoped_ptr(RValue& other="<<&other<<") current:["<<this<<"]"<<endl;ptr_=(reinterpret_cast<scoped_ptr&>(other).release()) ;} ~scoped_ptr() {cout<<"  ~scoped_ptr() current:["<<this<<"]"<<endl;enum { type_must_be_complete = sizeof(C) };delete ptr_;}template <typename U>scoped_ptr& operator=(scoped_ptr<U> rhs) {cout<<"scoped_ptr& operator=(scoped_ptr<U> ="<<&rhs<<") current:["<<this<<"]"<<endl;reset(rhs.release());return *this;}scoped_ptr& operator=(RValue& rhs) {cout<<"scoped_ptr& operator=(RValue& rhs="<<&rhs<<") current:["<<this<<"]"<<endl;swap(rhs);return *this;}void reset(C* p = NULL) {cout<<"void reset(C* p = "<<p<<") current:["<<this<<"]"<<endl;if (p != ptr_) {enum { type_must_be_complete = sizeof(C) };delete ptr_;ptr_ = p;}}C& operator*() const {cout<<"C& operator*() const current:["<<this<<"]"<<endl;assert(ptr_ != NULL);return *ptr_;}C* operator->() const  {cout<<"C* operator->() const current:["<<this<<"]"<<endl;assert(ptr_ != NULL);return ptr_;}C* get() const { cout<<"C* get() const current:["<<this<<"]"<<endl;return ptr_; }bool operator==(C* p) const { return ptr_ == p; }bool operator!=(C* p) const { return ptr_ != p; }void swap(scoped_ptr& p2) {cout<<"void swap(scoped_ptr& p2="<<p2<<")  current:["<<this<<"]"<<endl;C* tmp = ptr_;ptr_ = p2.ptr_;p2.ptr_ = tmp;}C* release()   {cout<<"C* release()  current:["<<this<<"]"<<endl;C* retVal = ptr_;ptr_ = NULL;return retVal;}template <typename PassAsType>scoped_ptr<PassAsType> PassAs() {cout<<"scoped_ptr<PassAsType> PassAs() current:["<<this<<"]"<<endl;return scoped_ptr<PassAsType>(release());}private:C* ptr_;template <class C2> bool operator==(scoped_ptr<C2> const& p2) const;template <class C2> bool operator!=(scoped_ptr<C2> const& p2) const;};#include "iostream"#include "myheader.h"using namespace std;class node{}; int _tmain(int argc, TCHAR* argv[], TCHAR* envp[]){// TODO: 在此处为应用程序的行为编写代码。cout<<"--------------constructor -------------------"<<endl<<endl;scoped_ptr<node> p11(new node());scoped_ptr<node> p22=p11.Pass();//这里不是‘=’的赋值,而是构造//p22=p11;//这样是错误的,因为operator =是privatecout<<"p11   "<<&p11<<"    p22   "<<&p22<<endl<<endl; cout<<"--------------operator = -------------------"<<endl;scoped_ptr<node> p1(new node());scoped_ptr<node> p2;cout<<"p1   "<<&p1<<"    p2   "<<&p2<<endl;p2=p1.Pass();//这里是赋值操作operator =system("pause");return 0;}//----------------------执行结果及分析--------------------------------------------------constructor -------------------//p11构造explicit scoped_ptr(C* p =0058D680):ptr_(p)current:[0025F9F4]//p11.pass()in the Pass() of [0025F9F4]//tmp1.scoped_ptr(RValue& other) scoped_ptr(RValue& other=0025F9F4) current:[0025F79C]//p11.release()释放持有的资源给tmp1C* release()  current:[0025F9F4]//本来pass中要调用tmp2.scoped_ptr(tmp1)[拷贝构造],但//这个函数是私有的。而编译器又发现有一个scoped_ptr(RValue& other)//函数可用来构造,但它要求参数是RValue的,进一步地,编译器发现//tmp1有个operator可实现此转化:operator rvalue_type&(),所以就//先调用了tmp1的operator rvalue_type&()来将tmp1从scoped_ptr转//到RValue类型,转化是安全的,因它们内部都只有一个指针数据。=======operator rvalue_type&() of [0025F79C]//调用完这个函数tmp2就构造好了 scoped_ptr(RValue& other=0025F79C) current:[0025F8C8]//tmp1用完了,它将其内部资源释放给tmp2、析构自己C* release()  current:[0025F79C]  ~scoped_ptr() current:[0025F79C]//同样的过程,p22.拷贝构造(tmp2)也是私有的,重复上述过程=======operator rvalue_type&() of [0025F8C8] scoped_ptr(RValue& other=0025F8C8) current:[0025F9E8]C* release()  current:[0025F8C8]  ~scoped_ptr() current:[0025F8C8]p11   0025F9F4    p22   0025F9E8/*另外通过汇编观察,主要是跟踪ecx和push的参数变化情况总结:进pass前,main中有一个局部变量名为tmp2,传给pass.pass内部也有一个局部变量名为tmp1p11初始化tmp1,tmp1初始化tmp2,tmp2初始化p22相当于tmp2是pass外面的一个临时变量,tmp1是pass里面的一个临时变量*/--------------operator = -------------------explicit scoped_ptr(C* p =0058D710) : ptr_(p) current:[0025F9DC]explicit scoped_ptr(C* p =00000000) : ptr_(p) current:[0025F9D0]p1   0025F9DC    p2   0025F9D0in the Pass() of [0025F9DC] scoped_ptr(RValue& other=0025F9DC) current:[0025F79C]C* release()  current:[0025F9DC]=======operator rvalue_type&() of [0025F79C] scoped_ptr(RValue& other=0025F79C) current:[0025F8F8]C* release()  current:[0025F79C]  ~scoped_ptr() current:[0025F79C]=======operator rvalue_type&() of [0025F8F8] scoped_ptr(RValue& other=0025F8F8) current:[0025F890]C* release()  current:[0025F8F8]scoped_ptr& operator=(scoped_ptr<U> =0025F890)  current:[0025F9D0]C* release()  current:[0025F890]void reset(C* p = 0058D710) current:[0025F9D0]  ~scoped_ptr() current:[0025F890]  ~scoped_ptr() current:[0025F8F8]请按任意键继续. . .  /*第二部分因为有个赋值操作,所以多了一次临时变量。在scoped_ptr模板中还有两个函数:template <typename U> scoped_ptr(scoped_ptr<U> other)template <typename U> scoped_ptr& operator=(scoped_ptr<U> rhs) 这两个函数原理一样:在c++03中,临时变量属于右值。它的性质与const &类似,即不能被改变。当pass()返回一个临时变量时(实际上是把有名变量变成无名临时的了),编译器要找一个拷贝构造或者类似这样的、带常引用参数的operator =:scoped_ptr& operator=(const scoped_ptr& rhs) 但,现实情况是scoped_ptr没有这样的函数,那么编译器接着找合适的函数,于是发现了上面两个函数可用。这就是它们存在的原因。同时,如果p2=p1的话,那么与上面相反,p1是有名变量,是个lvalue,不是const &型的,当然要匹配非-常引用参数的operator =或copy(T&),因为它们是私有的,所以就会报错。*/ /*三、其它:返回值优化(RVO),有了它,正常情况函数按值返回对象,里面来个临时变量,外面那个对象p2的拷贝构造会被调用一次,就完事了。但由于我们要实现move语义,而且是c++03版的语法,所以就有好几个临时变量。*/

原创粉丝点击