Zwracanie przez wartosc i referencje C++

Odpowiedz Nowy wątek
2018-01-18 16:27
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];
    }
}
edytowany 1x, ostatnio: hdw3, 2018-01-18 17:03

Pozostało 580 znaków

2018-01-18 17:19
kq
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[...]wac-operatory-w-mojej-klasie/


Pozostało 580 znaków

2018-01-18 17:33
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.

Pozostało 580 znaków

2018-01-18 17:36
kq
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.


Nie spodziewałem się, że będę musiał pisać na forum, w końcu to jedynie tablice i operatory, a jednak... jest nauczka;) - hdw3 2018-01-18 17:53

Pozostało 580 znaków

2018-01-18 17:56
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?

edytowany 1x, ostatnio: hdw3, 2018-01-18 17:56

Pozostało 580 znaków

2018-01-18 17:56
kq

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


Ok. Dziękuję za pomoc ;) - hdw3 2018-01-18 18:01

Pozostało 580 znaków

2018-01-18 17:58
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ą.


We are the 4p. Existence, as you know it, is over. We will add your biological and technological distinctiveness to our own. Resistance is futile
edytowany 1x, ostatnio: revcorey, 2018-01-18 18:01

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

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