这段代码是如何运行的?

时间:2011-12-31 05:47:48

标签: c++ memory-management smart-pointers

首先是代码,它来自'Ruminations on 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的构造函数之后调用它。
  2. Picture::Picture(P_Node* p_node)中,为什么不增加使用次数?这不是创建一个新的Picture
  3. 感谢您的帮助。

    我在Windows XP下使用VC6。

3 个答案:

答案 0 :(得分:1)

  

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

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

  

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

声明

frame()按值返回Picture个实例,但它被编码为返回Frame_pic*Frame_pic派生自P_nodePicture有一个接受P_node*的构造函数,frame()可以访问该构造函数,因此编译器允许它。

  

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

使用次数为P_node,而不是PicturePicture返回的frame()拥有Frame_pic创建的frame(),其使用计数成员已由Frame_pic构造函数设置为1。这就是Picture构造函数不会增加使用次数的原因 - 它已经是正确的值。

Frame_pic包含自己的Picture,它是从另一个Picture复制构造的,因此Picture构造函数需要增加原始{{1}的使用次数}}

答案 1 :(得分:0)

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

您使用其复制构造函数'p(pic)'初始化'p',因此它会按您看到的顺序调用

答案 2 :(得分:0)

  1. 复制构造函数由 Frame_Pic的构造函数调用(由初始化程序: p(pic)调用)。但是,在运行所有初始化程序之后,Frame_Pic的构造函数才会打印。
  2. 因为没有记录构造函数的预期用途,所以很难说。它可能是一个错误,或者它可能是“附加语义” - 也就是说,它可能正在考虑您对P_Node*进行手动控制,然后再将其归还的情况。但是附加语义不太可能,因为没有相应的分离机制来返回指针并清除它而不减少引用计数。所以,很可能是一个错误。
  3. 请注意,虽然这种手动引用计数可以作为学习练习,但现代C ++代码通常使用智能指针(例如std::shared_ptrboost::shared_ptrinvasive_ptr等)自动化过程。