C ++: Реализация конструктора копирования и оператора назначения копирования - PullRequest
16 голосов
/ 15 января 2011

Прочитав о конструкторах копирования и операторах копирования в C ++, я попытался создать простой пример. Хотя приведенный ниже фрагмент, очевидно, работает, я не уверен, правильно ли я реализую конструктор копирования и оператор назначения копирования. Не могли бы вы указать, есть ли какие-либо ошибки / улучшения или лучший пример для понимания соответствующих концепций.

class Foobase
{
    int bInt;

public:
    Foobase() {}

    Foobase(int b) { bInt = b;}

    int GetValue() { return bInt;}

    int SetValue(const int& val) { bInt = val; }
};


class Foobar
{
    int var;    
    Foobase *base;      

public:
    Foobar(){}

    Foobar(int v)
    {
        var = v;        
        base = new Foobase(v * -1);

    }

    //Copy constructor
    Foobar(const Foobar& foo)
    {       
        var = foo.var;
        base = new Foobase(foo.GetBaseValue());
    }

    //Copy assignemnt operator
    Foobar& operator= (const Foobar& other)
    {
        if (this != &other) // prevent self-assignment
        {
            var = other.var;
            base = new Foobase(other.GetBaseValue());

        }
        return *this;
    }

    ~Foobar()
    {
        delete base;
    }

    void SetValue(int val)
    {
        var = val;
    }

    void SetBaseValue(const int& val)
    {
        base->SetValue(val);
    }

    int GetBaseValue() const
    {
        return(base->GetValue());
    }

    void Print()
    {
        cout<<"Foobar Value: "<<var<<endl;
        cout<<"Foobase Value: "<<base->GetValue()<<endl;

    }   

};

int main()
{
    Foobar f(10);       
    Foobar g(f);  //calls copy constructor
    Foobar h = f; //calls copy constructor

    Foobar i;
    i = f;

    f.SetBaseValue(12);
    f.SetValue(2);    

    Foobar j = f = z; //copy constructor for j but assignment operator for f

    z.SetBaseValue(777);
    z.SetValue(77);

    return 1;
}

Ответы [ 3 ]

15 голосов
/ 15 января 2011

Ваш оператор копирования назначен неправильно. Объект, назначаемый для утечки, указывает на base.

Ваш конструктор по умолчанию также неверен: он оставляет как base, так и var неинициализированными, поэтому нет никакого способа узнать, является ли любой из них действительным и в деструкторе, когда вы вызываете delete base;, случается плохое. 1007 *

Самый простой способ реализовать конструктор копирования и оператор назначения копирования и узнать, что вы сделали это правильно, - это использовать идиома Копировать-и-Поменять .

2 голосов
/ 15 января 2011

Только Foobar требуется пользовательский конструктор копирования, оператор присваивания и деструктор. Foobase не нужен, потому что поведение компилятора по умолчанию достаточно хорошее.

В случае Foobar у вас есть утечка в операторе присваивания. Вы можете легко исправить это, освободив объект перед его выделением, и этого должно быть достаточно. Но если вы когда-нибудь добавите второй элемент указателя к Foobar, вы увидите, что тогда все становится сложнее. Теперь, если у вас есть исключение при выделении второго указателя, вам нужно правильно очистить первый выделенный указатель, чтобы избежать повреждения или утечек. И все становится сложнее, чем полиномиальным образом, когда вы добавляете больше указателей.

Вместо этого вы хотите реализовать оператор присваивания в терминах конструктора копирования. Затем вы должны реализовать конструктор копирования в терминах не-бросающей функции подкачки. Подробнее читайте об идиоме «Копировать и поменять».

Кроме того, конструктор по умолчанию Foobar не инициализирует элементы по умолчанию. Это плохо, потому что это не то, чего ожидает пользователь. Указатель члена указывает на произвольный адрес, а int имеет произвольное значение. Теперь, если вы используете объект, созданный конструктором, вы окажетесь очень близко от Земли неопределенного поведения.

1 голос
/ 15 января 2011

У меня есть очень простой патч для вас:

class Foobar
{
  int var;    
  std::unique_ptr<FooBase> base;

...

Это должно помочь вам начать.

Суть:

  1. НеЗвоните delete в вашем коде (эксперты видят пункт 2)
  2. Не звоните delete в вашем коде (вы знаете лучше ...)
...