/*
一、概述:
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.5 scoped_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 =是private
cout<<"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()释放持有的资源给tmp1
C* 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内部也有一个局部变量名为tmp1
p11初始化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 0025F9D0
in 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版的语法,所以就有好几个临时变量。
*/
scoped_ptr analysis
最新推荐文章于 2021-04-21 11:00:32 发布