2011-12-31 69 views
0

这里是代码首先,它来自 '反刍在C++' 第10章这段代码是如何运行的?

// TestCode.cpp : Defines the entry point for the console application. 
// 

#include "stdafx.h" 
#include <iostream> 
#include <string> 
#include <conio.h> 


using namespace std; 

class P_Node 
{ 
    friend class Picture; 
protected: 
    P_Node() : use(1) 
    { 

    } 
    virtual ~P_Node() 
    { 

    } 
private: 
    int use; 
}; 

class Picture 
{ 
    friend Picture frame(const Picture&); 
public: 
    Picture() : p(new P_Node) 
    { 
     cout << "Constructor\t" << "Picture::Picture()" << "\tcalled" << endl; 
     cout << "Picture p count\t" << p->use << endl; 
    } 
    Picture(const Picture& orig) : p(orig.p) 
    { 
     cout << "Copy Constructor\t" << "Picture::Picture(const Picture&)" << "\tcalled" << endl; 
     cout << "Picture p count\t" << p->use << endl; 
     orig.p->use++; 
    } 
    ~Picture() 
    { 
     cout << "Destructor\t" << "Picture::~Picture()" << "\tcalled" << endl; 
     cout << "Picture p count before decrease\t" << p->use << endl; 
     if(--p->use == 0) 
     { 
      cout << "Picture p count after decrease\t" << p->use << endl; 
      cout << "Deleted" << endl; 
      delete p; 
     } 
    } 
    Picture& operator=(const Picture& orig) 
    { 
     cout << "operator=\t" << "Picture& Picture::operator=(const Picture& orig)" << "\tcalled" << endl; 
     cout << "Picture p count before decrease\t" << p->use << endl; 
     orig.p->use++; 
     if(--p->use == 0) 
     { 
      cout << "Picture p count after decrease\t" << p->use << endl; 
      delete p; 
     } 
     p = orig.p; 
     return *this; 
    } 
private: 
    Picture(P_Node* p_node) : p(p_node) 
    { 
     // Why not p_node->use++? 
     cout << "Picture::Picture(P_Node* p_node)\tcalled" << endl; 
    } 
    P_Node *p; 
}; 

class Frame_Pic : public P_Node 
{ 
    friend Picture frame(const Picture&); 
private: 
    Frame_Pic(const Picture& pic) : p(pic) 
    { 
     cout << "Frame_Pic::Frame_Pic(const Picture& orig)" << "\tcalled" << endl; 
    } 
    Picture p; 
}; 

Picture frame(const Picture& pic) 
{ 
    return new Frame_Pic(pic); 
} 

int main(int argc, char* argv[]) 
{ 
    Picture my_pic; 
    frame(my_pic); 
    return 0; 
} 

结果是:

 
Constructor Picture::Picture() called 
Picture p count 1 
Copy Constructor Picture::Picture(const Picture&) called 
Picture p count 1 
Frame_Pic::Frame_Pic(const Picture& orig) called 
Picture::Picture(P_Node* p_node) called 
Destructor Picture::~Picture() called 
Picture p count before decrease 1 
Picture p count after decrease 0 
Deleted 
Destructor Picture::~Picture() called 
Picture p count before decrease 2 
Destructor Picture::~Picture() called 
Picture p count before decrease 1 
Picture p count after decrease 0 
Deleted 

我对这个代码的两个问题:

  1. 为什么在Frame_Pic的构造函数之前调用复制构造函数?在我看来,复制构造函数被调用,因为frame(my_pic)按值返回Picture。但是应该在Frame_Pic的Constructor之后调用它。
  2. Picture::Picture(P_Node* p_node),为什么不增加使用次数?这是不是创建一个新的Picture

感谢您的帮助。

我在Windows XP下使用VC6。

回答

1

1,为什么在Frame_Pic构造函数之前调用Copy构造函数?

因为p成员正在Frame_pic的构造函数的初始化列表中复制构造。初始化列表在输入构造函数的主体之前运行。

在我看来,复制构造函数被调用是因为frame(my_pic)正在通过值返回一个Picture。但是应该在Frame_Pic的构造函数之后调用它。

frame()宣布通过值来返回Picture实例,但是它被编码到返回Frame_pic*代替。Frame_picP_node派生,并Picture有一个接受P_node*一个构造函数,该构造函数是访问frame()所以编译器允许它。

2,In Picture :: Picture(P_Node * p_node),为什么不增加使用次数?这是不是创建一个新的图片?

的使用次数是P_node,不Picture。该Pictureframe()返回拥有Frame_picframe()创建,它的使用计数成员已经是1由Frame_pic构造。这就是为什么Picture构造函数不会增加使用计数 - 它已经在正确的值。

Frame_pic包含自己的Picture是拷贝构造从另一个Picture,使Picture构造需要增加原Picture的使用次数。

+0

感谢您的答案,但是我仍然对复制构造函数有疑问:如果我写了Picture'p = frame(my_pic)',复制构造函数会被调用吗?或者如果我写了'Picture p(frame(my_pic))',它会被调用吗?似乎如果我写这样的代码 – shengy 2011-12-31 07:52:23

+0

不会调用复制构造函数这取决于编译器优化。因为帧的'返回值()'是'Picture'由值,编译器可以决定默认的构建'p',通过隐藏的参考成'帧()'通过它,然后使用''=赋值操作符来填充它。 – 2011-12-31 20:29:31

0
Frame_Pic(const Picture& pic) : p(pic) 
{ 
    cout << "Frame_Pic::Frame_Pic(const Picture& orig)" << "\tcalled" << endl; 
} 

您初始化使用它的拷贝构造函数“P(PIC)”“P”,因此它被称为在你看到

+1

不,新的'Picture'是'框架()'收益不直接引用原'Picture',所以它不应该被递增使用计数。新的'Picture'包含一个新的'Frame_pic',然后引用原始的'Picture'。 'Frame_pic'确实增加了使用次数。原始代码运行正常。 – 2011-12-31 06:29:22

0
  1. 拷贝构造函数是由 Frame_Pic的构造函数调用顺序(这是由初始化程序: p(pic)调用)。但是,在所有初始化器运行之后,Frame_Pic的构造器才会打印。
  2. 由于构造函数的使用目的没有记录,所以很难说。这可能是一个错误,或者它可能是“附加语义” - 也就是说,它可能正在考虑您手动控制P_Node*,然后再回收的情况。然而,附加语义是不太可能的,因为没有相应的分离机制来返回指针并在不减少引用计数的情况下清除它。所以,最有可能的一个错误。

请注意,虽然这种手工引用计数可以很好的学习锻炼,现代C++代码通常使用智能指针(例如,std::shared_ptrboost::shared_ptrinvasive_ptr等)的过程自动化。

+0

我使用BoundsChecker检查代码是否有任何内存泄漏,原来的代码是正确的,如果我增加Picture :: Picture(P_Node *)中的数字,它将导致内存泄漏 – shengy 2011-12-31 06:11:18