Przeciążanie operatorów C++ i problemy z pamięcią

0

Witam!
Utworzyłem klasę "Tablice", która ma 3 pola: ```
int* tab; int sizeOfArr; int cellsTaken;

- dla "=" - wartości jednego obiektu kopiowane są do drugiego
- dla "+" - zwraca obiekt, którego pola mają wartości równe sumie odpowiadających pól sumowanych obiektów, czyli jak obiekt "t1" ma "size=1" i "t2" ma "size=3", to zwrócony będzie obiekt, z polem "size=4" i tak dla każdego pola.

Poniższa implementacja operatorów przechodzi kompilację, ale crashuje program jak dojdzie do wywołania tych operatorów:

Tablice Tablice::operator+(Tablice &t) {
Tablice temp;
temp.tab = new int[t.sizeOfArr + sizeOfArr];
temp.sizeOfArr = sizeOfArr + t.sizeOfArr;
temp.cellsTaken = cellsTaken + t.cellsTaken;
for (int i = 0; i < cellsTaken; i++) {
temp.tab[i] = tab[i];
}
int j = 0;
for (int i = cellsTaken; j < t.cellsTaken; i++) {
temp.tab[i] = t.tab[j];
j++;
}
return temp;
}

void Tablice::operator=(Tablice &t) {
//delete tab;
tab = new int[t.cellsTaken];
cellsTaken = t.cellsTaken;
sizeOfArr = t.sizeOfArr;
for (int i = 0; i < cellsTaken; i++) {
tab[i] = t.tab[i];
}
}



Tablice t;
Tablice t1;
Tablice t3;
t3=(t+t1);

Nie mam pojęcia czemu wywołanie destruktora crashuje program, nie widzę nigdzie miejsca, które sprawia, że "int* tab" jest usuwany dwukrortnie+, ponieważ nigdzie nie przypisywałem tego samego miejsca w pamięci do dwóch+ różnych wskaźników.

Tablice::~Tablice()
{
delete [] tab;
}


EDIT: Po dodaniu konstruktora kopiującego, którego wcześniej nie było, już śmiga, ale niestety nie wiem, w którym miejscu zostaje on użyty, ponieważ wydawało mi się, że do kopiowania używałem tylko przeciążonego "=" więc jak ktoś, komu się chciało przebrnąć przez ten post, wie czemu to pomogło to bym był wdzięczny za rozjaśnienie.(strzelałbym w miejscie gdzie zwracam obiekt w operator+, ale jak zwracam to przez referencję, zamiast kopii, to znowu otrzymuję błąd).

Ciało konstruktora kopiującego:

Tablice::Tablice(Tablice &pcOther) {
sizeOfArr = pcOther.sizeOfArr;
cellsTaken = pcOther.cellsTaken;
tab = new int[sizeOfArr];
for (int i = 0; i < pcOther.cellsTaken; i++) {
tab[i] = pcOther.tab[i];
}
}

2

http://en.cppreference.com/w/cpp/language/rule_of_three
http://en.cppreference.com/w/cpp/language/operators
Twój operator dodawania ma niezdefiniowane zachowanie (UB). Czytasz poza tablicą tab. Zwiększasz wszystkie rozmiary, a ta tablica ma rozmiar z obiektu *this.

for (int i = 0; i < cellsTaken; i++) {
        temp.tab[i] = tab[i]; // tutaj jest mniejsza od temp.tab
    } 
2

Konstruktor kopiujący wywoływany jest tutaj:

Tablice Tablice::operator+(Tablice &t)  {
 .....
 return temp;  // zwracamy kopię obiektu
}

Co do crasha, to w przypadku braku konstruktora kopiującego przekazujesz płytką kopię co oznacza że dwa obiekty współdzielą pamięć i w przypadku wywołania destruktora oba obiekty zwalniają tę samą pamięć. Dodatkowo jeden z nich może operować na już zwolnionej pamięci.

W przypadku zwracania wyniku przez referencje zwracasz uchwyt do obiektu stworzonego na stosie, co oznacza że po wyjściu z metody obiekt uż nie istnieje(!)

Generalnie każdy obiekt stworzony w bloku kodu jest usuwany zaraz po wyjściu z tego bloku - dotyczy obiektów tworzonych na stosie wywołania czyli bez new.

2
void Tablice::operator=(Tablice &t) {
    //delete tab;
    tab = new int[t.cellsTaken];

A ten komentarz przed delete tab to po co?
Jak myślisz, co się teraz dzieje z dotychczasowym tab?

2

Poniższa implementacja operatorów przechodzi kompilację (...)

Tablice Tablice::operator+(Tablice &t) { ... }
>
void Tablice::operator=(Tablice &t) { ... }
>
Tablice t;
Tablice t1;
Tablice t3;
>
t3 = ( t + t1); // !!!

Jakim cudem to przechodzi kompilację? Wynik dodawania jest r-wartością, a operator= może przyjąć tylko l-wartości (zresztą powinien zwracać referencję do obiektu this).

Dodaj const w parametrach.

0

Ja nie rozumiem po co się męczyć z zarządzaniem pamięcią, zamiast po prostu opakować std::vector i skorzystać z "rule of zero".
Całe badziewie, z którym masz problem zrobi się samo.

0 użytkowników online, w tym zalogowanych: 0, gości: 0