Как работает этот код? - PullRequest
       15

Как работает этот код?

0 голосов
/ 31 декабря 2011

Вот код в первую очередь, он взят из главы «Размышления на 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?

Спасибо за любую помощь.

Я использую VC6 под Windows XP.

Ответы [ 3 ]

1 голос
/ 31 декабря 2011

1, Почему конструктор копирования вызывается перед конструктором Frame_Pic?

Поскольку элемент p создается с помощью копирования в списке инициализации конструктора Frame_pic. Список инициализации выполняется до ввода тела конструктора.

На мой взгляд, конструктор копирования вызывается, потому что frame (my_pic) возвращает Picture по значению. Но это следует вызывать после Конструктора Frame_Pic.

frame() объявляется для возврата экземпляра Picture по значению, но он закодирован для возврата Frame_pic* вместо этого. Frame_pic происходит от P_node, а Picture имеет конструктор, который принимает P_node*, и этот конструктор доступен для frame(), так что компилятор это позволяет.

2, In Picture :: Picture (P_Node * p_node), почему бы не увеличить счетчик использования? разве это не создает новую Картинку?

Счетчик использования P_node, а не Picture. Picture, возвращаемое frame(), владеет Frame_pic, создаваемым frame(), чей счетчик использования уже равен 1 конструктором Frame_pic. Вот почему конструктор Picture не увеличивает счетчик использования - он уже имеет правильное значение.

Frame_pic содержит свой собственный Picture, созданный с помощью копирования из другого Picture, так что конструктору Picture необходимо увеличить счетчик использования исходного Picture.

0 голосов
/ 31 декабря 2011
  1. Конструктор копирования вызывается конструктором Frame_Pic (он вызывается инициализатором : p(pic)).Однако конструктор Frame_Pic не печатает до тех пор, пока не будут запущены все инициализаторы.
  2. Поскольку предполагаемое использование конструктора не задокументировано, трудно сказать.Это может быть ошибка или «присоединить семантику» - то есть, это может быть случай, когда вы берете ручное управление P_Node*, а затем возвращаете его.Однако семантика присоединения маловероятна, поскольку нет соответствующего механизма отсоединения, который бы возвращал указатель и очищал его, не уменьшая refcount.Так что, скорее всего, ошибка.

Обратите внимание, что хотя этот вид ручного подсчета ссылок может быть полезен в качестве учебного упражнения, современный код C ++ обычно использует умные указатели (например, std::shared_ptr или boost::shared_ptrinvasive_ptr и т. Д.) Для автоматизации процесса.

0 голосов
/ 31 декабря 2011
Frame_Pic(const Picture& pic) : p(pic)
{
    cout << "Frame_Pic::Frame_Pic(const Picture& orig)" << "\tcalled" << endl;
}

Вы инициализируете 'p', используя его конструктор копирования 'p (pic)', поэтому он вызывается в порядке, который вы видите

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...