2014-09-22 4 views
0

Я пытаюсь создать контейнер для мешков. Проблема, которая выше меня возникает, когда я перегружаю оператор =.Заблудиться при передаче параметра по ссылке, по значению

Zsak& Zsak::operator =(const Zsak& a) 
{ 
    (*this).V=a.V; 
    (*this).elemsz=a.elemsz; 
    return *this; 
} 

с этим заголовком:

class Zsak 
{ 
public: 
    Zsak(){V=new Elem[100];} 
    Zsak (const Zsak & a) 
    { 
     *this=a; 
    } 
    Zsak(int meret) 
    { 
     V=new Elem[meret]; 
    } 
    ~Zsak(){delete[] V;} 
    Zsak& operator -(const Zsak& b); 
    Zsak& operator =(const Zsak& a); 
    void Zsak_Ba(int e); 
    void Zsak_Bol(int e); 
    bool Uress(); 
    int E_Hany(int e) const; 
    friend std::ostream& operator << (std::ostream& out,const Zsak& z); 
private: 
    Elem *V; 
    int elemsz=0; 

}; 

Zsak_Ba помещает элемент в мешок;

Zsak_Bol вытягивает элемент из сумки;

То, что я наблюдал посредством тестирования, заключается в том, что адрес const Zsak a идентифицируется адресом *this.

с этим контекстом

Zsak z(5),c(5); 
z.Zsak_Ba(1); 
z.Zsak_Ba(1); 
z.Zsak_Ba(1); 
z.Zsak_Ba(2); 
z.Zsak_Ba(2); 
z.Zsak_Ba(2); 
z.Zsak_Ba(4); 
Zsak d=z; 
d.Zsak_Bol(1); 
cout<<z<<endl<<d; 

Он печатает:

1 2 
2 3 
4 1 

1 2 
2 3 
4 1 

И то, что он действительно должен напечатать это:

1 3 
2 3 
4 1 

1 2 
2 3 
4 1 

Что я должен сделать, чтобы получить это? Что я делаю неправильно? И почему?

Большое спасибо!

+2

Вы только копируете указатель здесь: '(* this) .V = a.V;'. Итак, теперь два объекта указывают на одни и те же данные. – juanchopanza

+0

А что делать, чтобы устранить это? – Iero

+0

Назначьте все элементы массива, на которые указывает объект RHS, на объекты массива, на которые указывает объект LHS. – juanchopanza

ответ

0

Вы копируете указатели (а не контент) в свой оператор присваивания.

Zsak& Zsak::operator =(const Zsak& a) 
{ 
    if (this == &a) { // or std::addressof(a) 
    return *this; 
    } 

    delete[] V; 

    elemsz=a.elemsz; 
    V=new Elem[elemsz]; 
    for (std::size_t i = 0; i < elemsz; ++i) { 
    V[i] = a.V[i]; 
    } 
    return *this; 
} 

Кроме того, я не вижу, где elemsz обновляется (вне инициализации членов). Я бы предположил, что это будет в конструкторах.

Zsak(int meret) 
{ 
    V=new Elem[meret]; 
    elemsz = meret; 
} 

И

Zsak() 
{ 
    V=new Elem[100]; 
    elemsz = 100; 
} 

Это может быть также стоит отметить, что часто «копировать-своп» используется для реализации оператора присваивания, и полную копию в конструктор копирования (в основном другой способ вокруг от того, что у вас есть).

«копировать-своп» будет выглядеть

Zsak (const Zsak & a) : elemsz(a.elemsz) 
{ 
    V = new Elem[elemsz]; 
    for (int i = 0; i < elemsz; ++i) { // copy the contents 
    V[i] = a.V[i]; 
    } 
} 

Zsak& Zsak::operator =(const Zsak& a) 
{ 
    Zsak temp(a); 
    std::swap(this->elemsz, temp.elemsz); 
    std::swap(this->V, temp.V); 
    return *this; 
} 

Он несет некоторые накладные расходы с командированным на себя, тест для самостоятельного присвоения может быть добавлен для этого, если это необходимо.

Понимая, что это задача для использования и реализации динамической памяти, может быть лучше перераспределить массив Elem и его управление вне основного класса. Как правило, легче поддерживать и исправлять ошибки и проблемы по мере их возникновения.

+0

@ Niall 'V = new Elem [elemsz]' будет удален при деконструировании вызовов? Я установил 'elemsz' здесь:' private: Elem * V; int elemsz = 0; 'Нехорошо это делать? – Iero

+1

@lero, да 'delete []' будет вызываться в деструкторе. Установка «elemsz» - хорошая идея, но вам нужно обновить ее, когда вы выделяете память в 'V'. – Niall

+0

Большое спасибо! Я смотрел этот код часами ... Еще раз спасибо! – Iero

0

Если вместо ручной динамической памяти вы используете vector<Elem>, вам не нужен какой-либо пользовательский конструктор копий или оператор присваивания. Он будет работать. Это предпочтительное решение. Пусть C++ сделает для вас работу.

+1

Я знаю это ... Но это задача :) Я должен делать это динамически. – Iero

Смежные вопросы