Zwracanie przez wartosc i referencje C++

0

Witam!

Przeciążam operator + i = w taki sposób:

Tablice Tablice::operator+(const Tablice &t) {
	Tablice temp;
	delete temp.tab;
	//przekopiuj wszystko do temp (nie wrzucam tego, zeby bylo czytelniej)
	return temp;
}

void Tablice::operator=(const 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];
	}
}

Wszystko działa, ale chcę uniknąć używania konstruktora kopiującego podczas używania operatora +. No to zmieniam:

Tablice& Tablice::operator+(const Tablice &t) {
	Tablice temp;
	delete temp.tab;
	//przekopiuj wszystko do temp (nie wrzucam tego, zeby bylo czytelniej)
	return temp;
}

Nie działa, debugger wyrzuca błąd w operatorze = w linii:

tab = new int[t.cellsTaken];

Zauważyłem, że działa gdy w operatorze + returna zmieni się na:

return *this;

Nie wiem czemu teraz nie rzuca błędem, ale zwracam nie to, co chciałem to zmieniam operator + tym razem na:


Tablice& Tablice::operator+(const Tablice &t) {
	Tablice temp;
	delete temp.tab;
	//przekopiuj wszystko do temp (nie wrzucam tego, zeby bylo czytelniej)
	Tablice* ptr = &temp;
        return *ptr;
}

Ale nie działa, co mnie nieszczególnie dziwi, ale nie wiem czemu w przypadku *this nie ma żadnych problemów.

Ostatecznie postanowiłem zwracać przez wskaźniki w taki sposób:

Tablice* Tablice::operator+(const Tablice &t) {
	Tablice temp;
	delete temp.tab;
	//przekopiuj wszystko do temp (nie wrzucam tego, zeby bylo czytelniej)
	Tablice* ptr = &temp;
	return ptr;
}

void Tablice::operator=(const 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];
	}
}

Ale teraz też nie działa i debugger wywala się w tej samej linijce, co wcześniej.
Nie jestem pewien, ale w tym przypadku może to być powodowane, że operator = dostaje kopię wskaźnika zwracanego z operatora + (jeżeli mówię głupoty to będę wdzięczny za sprostowanie), to spróbowałem ostatniej opcji, która mi przyszła do głowy:

void Tablice::operator=(const Tablice*&t) {


Ale teraz, to się nawet nie kompiluje i linker wywala się w main'ie:

int main()
{

	Tablice tab;
	Tablice t;

	tab.addLast(1);
	t.addLast(2);
	Tablice sum;
	sum = t + tab;      // w tym miejscu

	cout << sum;
    return 0;
}

Jak ktoś jest w stanie powiedzieć mi jak poprawnie się powinno zmienić operator +, aby nie używał konstruktora kopiującego lub
wytłumaczył czemu moje metody nie działają (gdzie najbardziej mnie ciekawi, czemu *this działa) będę bardzo wdzięczny.

EDIT:
Spróbowałem zmienić jeszcze w inny sposób, ale nie do końca działa. Printuje odpowiednią ilośc danych, ale zupełnie śmieciowe wartości, a po wyprintowaniu wyskakuje całą masa crash'y. Debugger nie wyrzuca mnie do żadnego miejsca w kodzie (w sumie po wyprintowaniu, juz nic nie ma), ale wyrzuca coś takiego : "wntll.pdb not loaded", a to już zupełnie nie wiem, co oznacza:

Tablice& Tablice::operator+(const Tablice &t) {
	Tablice temp;
	delete temp.tab;
	temp.sizeOfArr = sizeOfArr + t.sizeOfArr;
	temp.cellsTaken = cellsTaken + t.cellsTaken;
	temp.tab = new int[temp.sizeOfArr];
	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=(const 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];
	}
}
2

Z takim nazewnictwem to się nadaje na ioccc - i to nawet nie uwzględniając złego języka. Co to jest Tablice, i czemu to zwracasz? Z kodu wynika, że implementujesz swój std::vector<int>, ale jak to się ma do liczby mnogiej w nazwie?

    delete tab;

    tab = new int[(t)->cellsTaken];

Mieszasz new[] z delete. To UB, nawet niedawno pisałem o tym w artykule ;​).

Tablice& Tablice::operator+(const Tablice &t) {

Zwracasz referencję z operatora +, co nie ma sensu. Polecam lekturę: https://dsp.krzaq.cc/post/304/jak-przeladowywac-operatory-w-mojej-klasie/

0

Napisałem delete przez nieuwagę, kiedyś miałem to poprawić, ale zapomniałem i w efekcie został ten błąd do teraz, ale już zmieniłem. Co do nazwy, to faktycznie mogłaby być lepsza i po angielsku, ale to jest tylko program "testowy i do nauki", którego jedynym celem jest, żebym się w końcu przeciążania operatorów porządnie nauczył ;) Dzięki za podesłanie materiałów, poczytam i mam nadzieje, że w końcu się dowiem jak ominąć konstruktor kopiujący.

1

to jest tylko program "testowy i do nauki", którego jedynym celem jest, żebym się w końcu przeciążania operatorów porządnie nauczył ;)

A potem komuś dajesz do przeczytania i nie wiadomo o co chodzi :​P

mam nadzieje, że w końcu się dowiem jak ominąć konstruktor kopiujący.

Przy obecnym kodzie musisz włączyć optymalizację i liczyć na NRVO. W C++17 możesz wymusić RVO, ale nie wiem czy taka gimnastyka ma sens.

0

Nie jestem pewien czy dobrze zrozumiałem, ale czy to oznacza, że jeżeli chce, aby to działało musi zostać zwracanie obiektu Tablice w operatorze +, czyli musi pozostać użycie konstruktora kopiującego, bo pozbycie się tego konstruktora nie jest takie łatwe?

1

Tak. A potem kompilator za pomocą RVO/NRVO się zbędnych kopii pozbędzie. Zwracasz nowy obiekt, więc zwracasz wartość.

2

w dziale z materiałami dodałem Effective modern C++, masz tam między innymi o RVO. Poczytaj fajna książka.
zauważ przykłąd z netu:
std::vector<int> foo();
zwracamy teoretycznie przez wartość ale kompilator może się za nas zająć optymalizacją.

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