• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

destruktor sie nie wywoluje

Object Storage Arubacloud
0 głosów
496 wizyt
pytanie zadane 19 sierpnia 2020 w C i C++ przez lujasjeden Użytkownik (860 p.)

Dam tylko tą część kodu, która ma znaczenie:

main.cpp:

#include <iostream>
#include "polynomials.h"

using namespace std;

int main()
{
    Wx w;
    Px p;
    Result r;
//for (;;)
//{
    Polynomial *pointerWx;
    Polynomial *pointerPx;
    pointerWx=&w;
    pointerPx=&p;
    pointerWx->gather();
    pointerWx->show();
    pointerPx->gather();
    pointerPx->show();
    r.menu(w, p);
    r.showResult(w, p);
//}    
}

polynomials.h:

#include <iostream>
#include <stdio.h>
#include <cstdlib>
using namespace std;

class Polynomial
{
public:
    virtual void gather()=0;
    virtual void show()=0;
};

class Px;
class Wx;

class Result
{
protected:
    int resultDegree;
    int resultHelper;
    int choice;
    float *resultCoefficients;
public:
    void menu(Wx w, Px p);
    void addition(Wx w, Px p);
    void showResult(Wx w, Px p);
    Result(int=0, int=0, int=0);
    ~Result();

};

class Wx :public Polynomial
{
protected:
    string degreeStringNum;
    int degree;
    int helper;
    float *coefficients;

public:
    virtual void gather();
    virtual void show();
    void isInteger(string &s, int &i);
    friend class Result;

    Wx(string="0", int=0, int=0);
    ~Wx();

};

class Px :public Wx
{
public:
    virtual void gather();
    virtual void show();
    friend class Result;
    Px(string="0", int=0, int=0);
    ~Px();
};

structors.cpp:

#include <iostream>
#include "polynomials.h"

using namespace std;

Wx::Wx(string dNS, int d, int h)
{
    degreeStringNum=dNS;
    degree=d;
    helper=h;
    coefficients=new float[d+1];
    cout<<"Wx constructor called"<<endl;
}
Wx::~Wx()
{
    delete [] coefficients;
    cout<<"Wx destructor called"<<endl;
}

Px::Px(string dNS, int d, int h)
:Wx(dNS, d, h)
{
    coefficients=new float[d+1];
    cout<<"Px constructor called"<<endl;
}
Px::~Px()
{
    delete [] coefficients;
    cout<<"Px destructor called"<<endl;
}

Result::Result(int rD, int rH, int ch)
{
    resultDegree=rD;
    resultHelper=rH;
    choice=ch;
    resultCoefficients=new float[rD+1];
    cout<<"Result constructor called"<<endl;
}
Result::~Result()
{
    delete [] resultCoefficients;
    cout<<"Result destructor called"<<endl;
}

menu.cpp:

#include <iostream>
#include "polynomials.h"
using namespace std;

void Result::menu(Wx w, Px p)
{
    cout<<"Main menu"<<endl;
    cout<<"---------------------"<<endl;
    cout<<"1.Addition"<<endl;
    cout<<"2.Subtraction"<<endl;
    cout<<"3.Multiplication"<<endl;
    cout<<"4.Division"<<endl;
    cout<<"5.Exit"<<endl;
    cout<<endl;
    cout<<"Choose an operation: ";
    cin>>choice;

    switch(choice)
    {
    case 1:
        {
            cout<<"W(x)+P(x) = ";
            addition(w, p);
        }
        break;
    case 2:
        {
            cout<<"W(x)-P(x) = ";
            //subtraction();
        }
        break;
    case 3:
        {

        }
        break;
    case 4:
        {

        }
        break;
    case 5:
        {
            cout<<"Goodbye";
            exit(0);
        }
        break;
    default:
        {
            cout<<"There is no such option";
        }
    }
}

showResult.cpp:

#include <iostream>
#include "polynomials.h"
using namespace std;

void Result::showResult(Wx w, Px p)
{
    if (choice==1 || choice==2 || choice==3 || choice==4 || choice==5)
    {
    for (int i=resultDegree; i>=0; i--)
    {
        if (resultCoefficients[i]>0 && i!=resultHelper)
        {
            cout<<"+";
        }
        if (resultCoefficients[i]==-1 && i!=0)
        {
            cout<<"-";
        }
        if (resultCoefficients[i]!=0)
        {
            if ((resultCoefficients[i]!=1 && resultCoefficients[i]!=-1) || i==0)
            {
                cout<<resultCoefficients[i];
            }
            if (i!=0)
            {
                cout<<"x";
            }
            if (i!=0 && i!=1)
            {
                cout<<i;
            }
        }
        else if (resultCoefficients[i]==0)
        {
            resultHelper--;
        }
        if (i<=0 && resultHelper==-1)
        {
            cout<<"0";
        }
    }
    }
    cout<<endl;
    cout<<endl;
    cout<<"Press enter";
    getchar();getchar();
    system("cls");
}

jest taki output:

Wx constructor called
Wx constructor called
Px constructor called
Result constructor called
Input degree of polynomial W(x): 1
Input coefficients and constant of polynomial W(x):
1
1
W(x)= x+1

Input degree of polynomial P(x): 1
Input coefficients and constant of polynomial P(x):
1
1
P(x)= x+1

Main menu
---------------------
1.Addition
2.Subtraction
3.Multiplication
4.Division
5.Exit

Choose an operation: 1
W(x)+P(x) = Wx destructor called
Px destructor called
Wx destructor called
Wx destructor called
Px destructor called
Wx destructor called
2x+2

Press enter

i po nacisnieciu entera:

Wx destructor called
Px destructor called
Wx destructor called
Result destructor called
Px destructor called
Wx destructor called
Wx destructor called

Process returned 0 (0x0)   execution time : 26.947 s
Press any key to continue.

a gdy zamkne w nieskonczona petle w mainie program (zmaze komentarze) to mam tak:

Wx constructor called
Wx constructor called
Px constructor called
Result constructor called
Input degree of polynomial W(x): 1
Input coefficients and constant of polynomial W(x):
1
1
W(x)= x+1

Input degree of polynomial P(x): 1
Input coefficients and constant of polynomial P(x):
1
1
P(x)= x+1

Main menu
---------------------
1.Addition
2.Subtraction
3.Multiplication
4.Division
5.Exit

Choose an operation: 1
W(x)+P(x) = Wx destructor called
Px destructor called
Wx destructor called
Wx destructor called
Px destructor called
Wx destructor called
2x+2

Press enter

i po nacisnieciu entera:

Wx destructor called
Px destructor called
Wx destructor called
Input degree of polynomial W(x):

nawet resultDestruktor nie zadzwonil, jak to rozwiazac? bo chcialbym zeby to bylo zapetlone a nie chce zeby doszlo do memory leaku, no i nawet jak to nie jest zapetlone to nie dziala tak jakbym chcial, bo program najpierw maze ekran konsoli a potem dopiero wywoluja sie te ostatnie destruktory, jak dam system("cls") do destruktora Result to nawet nie maze ekranu bo sie nie wywoluje ;p

2 odpowiedzi

+1 głos
odpowiedź 19 sierpnia 2020 przez Piotr Batko Stary wyjadacz (13,190 p.)

Destruktor obiektu r nigdy nie jest uruchamiany w trakcie pracy pętli for z maina, bo r żyje dłużej niż ta pętla. Jak chcesz, żeby po każdym pełnym obiegu pętli r było niszczone i ponownie tworzone na początku pętli, to przesuń sobie linijkę 10. z maina do środka pętli. W obecnym kodzie r jest niszczone dopiero na koniec funkcji main.

I to obecne rozwiązanie jest w ogóle w miarę ok jeżeli chodzi o zabezpieczanie przed wyciekami pamięci. Tzn. tworzysz obiekt r, rusza konstruktor i alokuje pamięć. Korzystasz sobie z tego, drukujesz nawet wielokrotnie w pętli, a jak się już pobawiłeś, to pętla się kończy, main się kończy i rusza destruktor. Zwalnia pamięć i wszystko gra, nie ma wycieków :) A napisałem, że to rozwiązanie jest w "miarę ok", a nie że jest dobre, bo dobre by tutaj było zastosowanie Rule of Zero ;)

komentarz 21 sierpnia 2020 przez lujasjeden Użytkownik (860 p.)
Mógłbyś przybliżyć temat? Bo czytając o tym w języku angielskim jest mi ciężko to zrozumieć bo nawet nie znam tych zagadnień po polsku?
2
komentarz 21 sierpnia 2020 przez j23 Mędrzec (194,920 p.)

W skrócie chodzi o to, by przy tworzeniu klas korzystać z typów, które mają zaimplementowaną semantykę kopiowania i przenoszenia, dzięki czemu nie trzeba implementować operatora przypisania, konstruktora kopiującego i destruktora, ponieważ domyślne implementacje zrobią całą robotę. Innymi słowy nie trzymać łańcucha znakowego w zmiennej typu char*, tylko std::string, wszelkiej maści bufory w std::vector, zamiast jechać na gołych wskaźnikach z new[]/delete[].

komentarz 21 sierpnia 2020 przez lujasjeden Użytkownik (860 p.)
Też już wcześniej ktoś zwrócił mi uwagę abym skorzystał z wektora zamiast new/delete, nawet nie wiem czy nie ty :p, ale wtedy byłem na tyle początkujący (nadal jestem), że nie wiedziałem nawet o czym piszesz. Wykorzystałem new i delete to już na tym dokończę ten projekt, czy cos powinienem dodać do kodu w takim razie? Tzn coś z tych 5 czy 6 specjalnych funkcji klas do którychś z klas.
1
komentarz 21 sierpnia 2020 przez Piotr Batko Stary wyjadacz (13,190 p.)

j23 bardzo fajnie wyjaśnił temat. Pozwolę sobie troszeczkę uzupełnić tę odpowiedź.

Może jeszcze wcześniej zapoznaj się z regułą trzech. Czytaj dalej, jak już załapiesz regułę trzech :)

Reguła zera mówi, że najlepiej zrobić tak, żeby nie pisać żadnej z tych trzech funkcji. Np. jeżeli zrobiłeś sobie w klasie wskaźnik, żeby dynamicznie alokować tablicę to masz problem, bo musisz napisać te 3 funkcje. Ale jeżeli użyłbyś do tego celu std::vector-a, to nie musisz nic pisać. Ten domyślnie utworzony destruktor przecież poprawnie skasuje wektor. Domyślny konstruktor kopiujący poprawnie będzie go kopiował, a operator przypisania poprawnie przypisywał. (Tak, wiem, napisałem to samo co j23, tylko innymi słowami :) )

1
komentarz 21 sierpnia 2020 przez j23 Mędrzec (194,920 p.)

W innym wątku wspomniałem, byś argumenty funkcji które są klasami przekazywał przez [const] referencję.

komentarz 21 sierpnia 2020 przez lujasjeden Użytkownik (860 p.)
Więc napiszę ten program w ten sposób jaki mam a potem jeszcze raz z użyciem wektora. Dlaczego powinienem używać  const referencji? Skąd mam wiedzieć które typy mają zaimplementowaną semantykę kopiowania i przenoszenia?

Teraz musze w każdej klasie która ma wskaźnik dynamiczny napisać 3 funkcje z reguły trzech tak?
1
komentarz 21 sierpnia 2020 przez j23 Mędrzec (194,920 p.)

Dlaczego powinienem używać  const referencji?

Referencji używasz po to, żeby obiekt nie był niepotrzebnie kopiowany, a const dajesz wtedy, gdy chcesz przekazać obiekt tylko do odczytu. Tu uwaga: tylko metody const mogą być wywoływane na rzecz obiektu stałego.

Skąd mam wiedzieć które typy mają zaimplementowaną semantykę kopiowania i przenoszenia?

Z dokumentacji.

Teraz musze w każdej klasie która ma wskaźnik dynamiczny napisać 3 funkcje z reguły trzech tak?

Najlepiej pięć (semantyka przenoszenia) ;) Posiadanie wskaźnika nie wymusza od razu implementacji tych metod. Jeśli klasa nie jest właścicielem pamięci, a jedynie jej używa (nie zwalnia), to nie trzeba implementować. Zasada trzech jest prosta: jeśli twoja klasa musi mieć zaimplementowany ctor kopiujący lub destruktor lub operator przypisania, to znaczy, że najprawdopodobniej potrzebuje implementacji ich wszystkich. I tyle.

komentarz 21 sierpnia 2020 przez lujasjeden Użytkownik (860 p.)

ok, przyznam, ze jest to mega wymagajace dla mnie, nawet samo zdeklarowanie ale mam tak:

polynomials.h:

class Result
{
protected:
    string choiceStringNum;
    int resultDegree;
    int resultHelper;
    int choice;
    float *resultCoefficients;
public:
    void menu(Wx w, Px p);
    void addition(Wx w, Px p);
    void subtraction(Wx w, Px p);
    void showResult(Wx w, Px p);
    void isInteger(string &s, int &i);

    Result(string="0", int=0, int=0, int=0); //constructor
    Result(const Result &copyResult);  //copy constructor
    Result& operator=(Result copyOperator); //copy assignment operator
    Result(Result &&moveResult);    //move constructor
    Result& operator=(Result&& moveOperator); //move assignment operator

    ~Result();
};

structors.cpp:

Result::Result(string chSN, int rD, int rH, int ch)
{
    choiceStringNum=chSN;
    resultDegree=rD;
    resultHelper=rH;
    choice=ch;
    resultCoefficients=new float[rD+1];
    //cout<<"Result constructor called"<<endl;
}

Result::Result(const Result &cR)
{
    cout<<"copyResult constructor called"<<endl;
}

Result& operator=(const Result &cR)
{
        cout<<"copy assignment operator called "<<endl;
        return *this;
}

Result::Result(Result &&mR) //noexcept , co znaczy?
{
    cout<<"moveResult constructor called"<<endl;
}

Result& operator=(Result&& mR)
{
    cout<<"move assignment operator called"<<endl;

    if (this!=&cR) //dlaczego 1 ampersand?
    {
        //delete, skopiuj atrybuty od Result
        //nullptr co znaczy?
    }
    return *this;
}

Result::~Result()
{
    delete [] resultCoefficients;
    cout<<"Result destructor called"<<endl;
}

mam taki error:

 kopia\structors.cpp|47|error: 'Result& operator=(const Result&)' must be a nonstatic member function|
 kopia\structors.cpp|58|error: 'Result& operator=(Result&&)' must be a nonstatic member function|

i mam pare pytan:

0.Dlaczego taki error, co jest nie tak zapisane? Czy cokolwiek jest dobrze zapisane ;p?

1.W kopie konstruktora wrzucic wszystkie atrybuty Result i przyrownac je do cR? W taki sposob:

Result::Result(const Result &cR)
{
    cout<<"copyResult constructor called"<<endl;

choiceStringNum=cR;
resultDegree=cR;
resultHelper=cR;
choice=cR;
*resultCoefficients=cR;
}

2.Co sie daje w oba operatory przypisania? W operator przenoszący coś spisałem z neta ale przyznam, że zielonego pojęcia nie mam co i dlaczego.

Co znaczy nullptr?

Co robi zapis return *this; (dlaczego z gwiazdką też)

3.W konstruktor przenoszący dać atrybuty klasy Result przyrownane do mR? W taki sposob:

Result::Result(Result &&mR) //noexcept , co znaczy?
{
    cout<<"moveResult constructor called"<<endl;

choiceStringNum=mR;
resultDegree=mR;
resultHelper=mR;
choice=mR;
*resultCoefficients=mR;
}

co znaczy noexcept? co robi?

Tu jeszcze na jednej stronie pisze aby w konstruktorze przenoszenia zrobic to:

Przypisz elementy członkowskie danych obiektu źródłowego do wartości domyślnych. Zapobiega to wykorzystaniu przez destruktora zasobów (takich jak pamięć) wiele razy.

Zrobic tak?

No i ogolnie wszelakie uwagi mile widziane

 

1
komentarz 21 sierpnia 2020 przez j23 Mędrzec (194,920 p.)
edycja 21 sierpnia 2020 przez j23

0. Zapomniałeś o Result:: przy operator= w pliku .cpp

1. Nie. Tak ma być:

Result::Result(const Result &cR)
{
    choiceStringNum = cR.choiceStringNum;
    resultDegree = cR.resultDegree;
    resultHelper = cR.resultHelper;
    choice = cR.choice;
    resultCoefficients = new float[resultDegree + 1];
    std::copy(cR.resultCoefficients, cR.resultCoefficients + resultDegree + 1, resultCoefficients);
}

2. prawie to samo co w konstruktorach, ale możesz zrobić tak:

Result& operator=(Result cR)
{
    std::swap(choiceStringNum, cR.choiceStringNum);
    std::swap(resultDegree, cR.resultDegree);
    std::swap(resultHelper, cR.resultHelper);
    std::swap(choice, cR.choice);
    std::swap(resultCoefficients, cR.resultCoefficients);
    return *this;
}

I za jednym zamachem masz zaimplementowany operator przypisania i przenoszenia ;)

3.) ctor będzie wyglądał tak samo jak ctor kopiujący z wyjątkiem linii z resultCoefficients, tu wystarczy:

resultCoefficients = cR.resultCoefficients;
cR.resultCoefficients = nullptr;
cR.resultDegree = 0;

noexcept oznacza, że metoda nie będzie rzucać wyjątkiem (info dla kompilatora).

nullptr to umowna wartość wskaźnika z nieprzypisaną pamięcią.

komentarz 21 sierpnia 2020 przez lujasjeden Użytkownik (860 p.)

0) I o const w nawiasie w .h

1)

std::copy(cR.resultCoefficients, cR.resultCoefficients + resultDegree + 1, resultCoefficients);

nie rozumiem tej linijki, dlaczego drugi argument nie jest w nawiasach kwadratowych, tzn no tez wiem ze dziwnie jakby byl w nawiasach kwadratowych ale i tak nie rozumiem tego, moze umiesz jakos to opisac

2) Czy na pewno ma byc 1 ampersand przy mR albo moze pomyliles mR z cR, czy wszystko jest ok? Poza tym w tym jednym zapisie mam zalatwione oba operatory (kopiujacy i przenoszacy?) 

3) Tzn rozumiem, ze cR zamienic na mR?

4) Uzywac tego noexcept? I jak tak to gdzie dokladnie, przy ktorych z tych 6 funkcji?

5) Poza tym myslisz, zeby dac kazda klase w odzielny plik czy niech te 3 klasy beda w 1 pliku, bo w sumie troche kodu sie zrobi jak zaimplementuje to do 3 klas

1
komentarz 21 sierpnia 2020 przez j23 Mędrzec (194,920 p.)

1. Drugi argument ma wskazywać na pozycję za ostatnim elementem tablicy, czyli dwa pierwsze parametry opisują przedział do skopiowania.

2. Ampersand - tak, i tak, pomyliłem mR z cR.

Poza tym w tym jednym zapisie mam zalatwione oba operatory (kopiujacy i przenoszacy?) 

Tak.

3. Tak.

4. Nie musisz.

5. W dobrym stylu jest każdą klasę dać w oddzielnym pliku.

komentarz 21 sierpnia 2020 przez lujasjeden Użytkownik (860 p.)

5)Kazda deklaracje klasy w osobnym pliku oraz kazda definicje klasy w osobnym pliku czy moze deklaracje oraz definicje w jednym ale kazda klase oddzielnie? Jak bys to widzial, bo to 1 moj projekt oop.

 

Oraz:

https://docs.microsoft.com/pl-pl/cpp/cpp/move-constructors-and-move-assignment-operators-cpp?view=vs-2019

 

Tu pisze aby zwalniac pamiec w operator przypisania przenoszenia

1
komentarz 21 sierpnia 2020 przez j23 Mędrzec (194,920 p.)

Może być:

  • .h i .cpp dla każdej klasy oddzielnie
  • jeden .h i wiele .cpp
  • każda klasa (w całości) w oddzielnym pliku .h

Rób, jak Ci pasi.

komentarz 21 sierpnia 2020 przez lujasjeden Użytkownik (860 p.)
dzieki wielkie! a rzucisz jeszcze okiem na to zwalnianie pamieci w operatorze przenoszenia
1
komentarz 21 sierpnia 2020 przez j23 Mędrzec (194,920 p.)
Pokaż go.
komentarz 21 sierpnia 2020 przez lujasjeden Użytkownik (860 p.)
https://docs.microsoft.com/pl-pl/cpp/cpp/move-constructors-and-move-assignment-operators-cpp?view=vs-2019

 

z tego artykulu

a operator przeniesienia to wyrzucic z kodu w ogole w takim razie, jezeli kopiujacy spelnia role obu?
1
komentarz 21 sierpnia 2020 przez j23 Mędrzec (194,920 p.)

Jakbyś robił oddzielnie operatory, to oczywiście powinieneś zwalniać pamięć. W mojej propozycji zwalnianiem pamięci zajmuje się destruktor parametru cR.

jezeli kopiujacy spelnia role obu?

Ja bym go nazwał kopiująco-przenoszący (uniwersalny?).

komentarz 21 sierpnia 2020 przez lujasjeden Użytkownik (860 p.)

nie wiem dlaczego ale:

.h

Result& operator=(const Result& copyOperator); //copy assignment operator

.cpp

Result& Result::operator=(const Result& cR)    //copy assignment operator
{
        cout<<"copy assignment operator called "<<endl;
        swap(choiceStringNum, cR.choiceStringNum);
        swap(resultDegree, cR.resultDegree);
        swap(resultHelper, cR.resultHelper);
        swap(choice, cR.choice);
        swap(resultCoefficients, cR.resultCoefficients);

        return *this;
}

majac tak mam:

 kopia\structors.cpp|56|error: no matching function for call to 'swap(std::__cxx11::string&, const string&)'|

a gdy usune w obu miejscach const (te w nawiasach) to dziala XD, 

no a tego move assignment operatora to wyrzucic z .h i z cpp tak?

1
komentarz 22 sierpnia 2020 przez j23 Mędrzec (194,920 p.)

Ten operator kopiujący jest źle zrobiony. On nie kopiuje, tylko zamienia miejscami wartości pól (dlatego z const nie działa). Pisałem Ci wcześniej, że operator kopiowania jest bardzo podobny do konstruktora kopiującego. W operatorze trzeba zwolnić starą pamięć (o czym też pisaliśmy).

komentarz 22 sierpnia 2020 przez lujasjeden Użytkownik (860 p.)

najwidoczniej zle sie zrozumielismy,

copy assignment operator:

Result& Result::operator=(const Result& cR)    //copy assignment operator
{
        cout<<"copy assignment operator called "<<endl;
        
        if (this != &cR)
        {
            delete [] resultCoefficients;

            choiceStringNum=cR.choiceStringNum;
            resultDegree=cR.resultDegree;
            resultHelper=cR.resultDegree;
            choice=cR.choice;

            resultCoefficients = new float[cR.resultDegree + 1];
            for (int i=resultDegree; i>=0; i--)
            {
                resultCoefficients[i]=cR.resultCoefficients[i];
            }
            copy(cR.resultCoefficients, cR.resultCoefficients + resultDegree + 1, resultCoefficients);
        }
        return *this;
}

move assignment operator:

Result& Result::operator=(Result&& mR)      //move assignment operator
{
    cout<<"move assignment operator called"<<endl;

    if (this!=&mR) 
    {
        delete [] resultCoefficients;
        
        choiceStringNum = mR.choiceStringNum;
        resultDegree = mR.resultDegree;
        resultHelper = mR.resultHelper;
        choice = mR.choice;
        resultCoefficients = mR.resultCoefficients;
        mR.resultCoefficients = nullptr;
        mR.resultDegree = 0;
    }
    return *this;
}

Czy w ten sposob ma to wygladac?

1
komentarz 22 sierpnia 2020 przez j23 Mędrzec (194,920 p.)

Operator przenoszący wygląda OK, ale kopiujący popraw:

  • Linia 11: złe pole przypisujesz.
  • Linie 15-18: Po co tam jest ta pętla, skoro masz std::copy? Dlaczego kopiujesz od końca zamiast po ludzku od początku? Czy to + 1 przy new jest po to, by ta pętla działała poprawnie?

[dodane]

W przenoszącym zrób:

choiceStringNum = std::move(mR.choiceStringNum);

Nie zwróciłem uwagi, że to std::string.

komentarz 22 sierpnia 2020 przez lujasjeden Użytkownik (860 p.)

ok tak zrobie, ogolnie siedze chyba 4h i proboje znalezc blad bo program sie crashuje nieraz, nieraz dziala dobrze a nieraz sie crashuje, ogolnie doszedlem do wniosku ze problem jest w klasie Result bo jak wywoluje jej funkcje to wtedy program sie crashuje (nieraz), jak je dam sobie w komentarze no to ta nieskonczona petla dziala dobrze konstruktory i destruktory dzialaja dobrze i moge w nieskonczonosc pobierac i wypisywac wielomiany. Te funkcje od Result wygladaja tak:

menu.cpp:

#include <iostream>
#include "polynomials.h"
using namespace std;

void Result::menu(Wx w, Px p)
{
    cout<<"Main menu"<<endl;
    cout<<"---------------------"<<endl;
    cout<<"1.Addition"<<endl;
    cout<<"2.Subtraction"<<endl;
    cout<<"3.Multiplication"<<endl;
    cout<<"4.Division"<<endl;
    cout<<"5.Exit"<<endl;
    cout<<endl;
    cout<<"Choose an operation: ";
    w.isInteger(choiceStringNum, choice);
    while (choice!=1 && choice!=2 && choice!=3 && choice!=4 && choice!=5)
    {
        cout<<"There is no such option, try again: ";
        w.isInteger(choiceStringNum, choice);
    }

    switch(choice)
    {
    case 1:
        {
            cout<<"W(x)+P(x) = ";
            addition(w, p);
        }
        break;
    case 2:
        {
            cout<<"W(x)-P(x) = ";
            subtraction(w, p);
        }
        break;
    case 3:
        {

        }
        break;
    case 4:
        {

        }
        break;
    case 5:
        {
            cout<<"Goodbye";
            exit(0);
        }
        break;
    default:
        {
            cout<<"There is no such option";
        }
    }
}

showResult.cpp:

#include <iostream>
#include "polynomials.h"
using namespace std;

void Result::showResult(Wx w, Px p)
{
    if (choice==1 || choice==2 || choice==3 || choice==4 || choice==5)
    {
    for (int i=resultDegree; i>=0; i--)
    {
        if (resultCoefficients[i]>0 && i!=resultHelper)
        {
            cout<<"+";
        }
        if (resultCoefficients[i]==-1 && i!=0)
        {
            cout<<"-";
        }
        if (resultCoefficients[i]!=0)
        {
            if ((resultCoefficients[i]!=1 && resultCoefficients[i]!=-1) || i==0)
            {
                cout<<resultCoefficients[i];
            }
            if (i!=0)
            {
                cout<<"x";
            }
            if (i!=0 && i!=1)
            {
                cout<<i;
            }
        }
        else if (resultCoefficients[i]==0)
        {
            resultHelper--;
        }
        if (i<=0 && resultHelper==-1)
        {
            cout<<"0";
        }
    }
    }
    cout<<endl;
    cout<<endl;
    cout<<"Press enter";
    getchar();getchar();
    system("cls");
}

a main tak:

#include <iostream>
#include "polynomials.h"

using namespace std;

int main()
{
    for (;;)
    {
        Wx w;
        Px p;
        Result r;

        Polynomial *pointerWx;
        Polynomial *pointerPx;
        pointerWx=&w;
        pointerPx=&p;
        pointerWx->gather();
        pointerWx->show();
        pointerPx->gather();
        pointerPx->show();
        //r.menu(w, p);
       // r.showResult(w, p);
    }
}

no i ogolnie no to do obu tych funkcji sa przesylane objekty (w i p) w tym siedzi problem? zle jest to robione? ale kurde dzialalo jeszcze wczoraj caly czas dopoki nie zabralem sie za te konstruktory i operatory przypisania wszystkie no i za funkcje isFloat ale ja dalem tez w komentarze, zreszta wywolywana byla tylko podczas sprawdzania czy input jest floatem, czyli w gatherWx i gahterPx czyli przed tymi dwoma co powoduja blad, co tu potencjalnie moze byc nie tak, czy niedopisane konstruktory tak jak u Result powoduja ten blad? ale nie wydaje mi sie skoro akurat ta czesc kodu nie powoduje bledu, a moze te wszystkie konstruktory Result jest z nimi cos nie tak? 

Jak crashuje to jest taki komunikat:

Process returned -1073741819 (0xC0000005)   execution time : 4.540 s
Press any key to continue.

 

1
komentarz 22 sierpnia 2020 przez j23 Mędrzec (194,920 p.)
Pokaż konstruktory kopiujące.
komentarz 22 sierpnia 2020 przez lujasjeden Użytkownik (860 p.)
Result::Result(const Result &cR)      //copy constructor
{
    cout<<"copyResult constructor called"<<endl;
    choiceStringNum = cR.choiceStringNum;
    resultDegree = cR.resultDegree;
    resultHelper = cR.resultHelper;
    choice = cR.choice;
    resultCoefficients = new float[resultDegree + 1];
    copy(cR.resultCoefficients, cR.resultCoefficients + resultDegree + 1, resultCoefficients);
}

wlasnie nie powinno byc w nawiasie zamiast resultDegree+1 rD+1 no bo zwykly konstruktor wyglada tak:

Result::Result(string chSN, int rD, int rH, int ch)     //constructor
{
    choiceStringNum=chSN;
    resultDegree=rD;
    resultHelper=rH;
    choice=ch;
    resultCoefficients=new float[rD+1];
    cout<<"Result constructor called"<<endl;
}

a do Wx i Px jeszcze nie mam teraaz to robie, a i czy musze do Px robic skoro on dziedziczy od Wx? czy ttego tez nie odziedziczy tak samo jak nie dziedziczyl konstruktora i destruktora

1
komentarz 22 sierpnia 2020 przez j23 Mędrzec (194,920 p.)

a do Wx i Px jeszcze nie mam

Ech, skoro nie masz, a powinieneś mieć, to dlaczego założyłeś, że kod będzie działać?

komentarz 22 sierpnia 2020 przez lujasjeden Użytkownik (860 p.)
no bo wczoraj dzialal bez zadnego z nich, ale ok mozliwe ze jesli dodalem do Result to musze tez juz dodac do Wx oraz Px, no i ponawiam moje pytania z poprzedniej odpowiedzi oraz czy jezeli mam w Wx oraz Px kolejny wskaznik to jego tez rozumiem mam kopiowac copy?
komentarz 22 sierpnia 2020 przez lujasjeden Użytkownik (860 p.)
Wx::Wx(const Wx &cWx)      //copy constructor
{
    cout<<"copyWx constructor called"<<endl;
    
    degreeStringNum = cWx.degreeStringNum;
    coefficientsStringNum = coefficientsStringNum=new string[d+1]
    degree = cWx.degree;
    helper = cWx.helper;
    coefficients=new float[d+1];
    copy(cWx.coefficients, cWx.coefficients + degree + 1, coefficients);
    copy(cWx.CoefficientsStringNum, cWx.CoefficientsStringNum + Degree + 1, CoefficientsStringNum);
}

copy constructor dla Wx, pytanie czy powinienem pisac d czy degree zarowno jak i w copy jak i  w []

1
komentarz 22 sierpnia 2020 przez j23 Mędrzec (194,920 p.)

no bo wczoraj dzialal bez zadnego z nich

Na tym właśnie polega trudność w ręcznym zarządzaniu pamięcią. Jak zrobisz błąd, to on nie musi od razu wyjść. Kod raz zadziała, raz nie. I dlatego powinieneś trzymać się zasad (rule of three/five). No i generalnie unikać ręcznego zarządzania pamięcią (vide std::string, std::vector itd.).

Px nie ma pól, które trzeba specjalnie traktować, więc nie musisz mu implementować operatorów, konstruktorów i destruktora. Domyślne implementacje wystarczą.

W pierwotnym kodzie klasa Px posiada destruktor, który - nie wiedzieć czemu - zwalania pamięć, której właścicielem jest klasa Wx - to błąd. Usuń go!

 

1
komentarz 22 sierpnia 2020 przez j23 Mędrzec (194,920 p.)

pytanie czy powinienem pisac d czy degree

Skoro alokujesz d + 1 elementów, to i skopiować powinieneś d + 1 elementów.

komentarz 22 sierpnia 2020 przez lujasjeden Użytkownik (860 p.)

Ok biore sie do pracy, 

Px nie ma pól, które trzeba specjalnie traktować, więc nie musisz mu implementować operatorów, konstruktorów i destruktora. Domyślne implementacje wystarczą.

 myslalem, ze skoro dziedziczy od Wx wszystkie jego atrybuty no to posiada rowniez np *coefficients ktore trzeba zwolnic. ok czyli wyrzucam wlasciwie i konstruktor i destruktor.

 

komentarz 22 sierpnia 2020 przez lujasjeden Użytkownik (860 p.)

Skoro alokujesz d + 1 elementów, to i skopiować powinieneś d + 1 elementów.

Wx::Wx(string dNS, int d, int h) //constructor
{
    degreeStringNum=dNS;
    degree=d;
    helper=h;
    coefficients=new float[d+1];
    coefficientsStringNum=new string[d+1]; //sprawdz potem nullptr

    cout<<"Wx constructor called"<<endl;
}

Wx::Wx(const Wx &cWx)      //copy constructor
{
    cout<<"copyWx constructor called"<<endl;

    degreeStringNum = cWx.degreeStringNum;
    degree = cWx.degree;
    helper = cWx.helper;

    coefficients=new float[d+1];
    coefficientsStringNum = coefficientsStringNum=new string[d+1];
    copy(cWx.coefficients, cWx.coefficients + d + 1, coefficients);
    copy(cWx.coefficientsStringNum, cWx.coefficientsStringNum + d + 1, coefficientsStringNum);
}

mam:

 kopia\classWx.cpp|25|error: 'd' was not declared in this scope|

a dla degree dziala 

1
komentarz 22 sierpnia 2020 przez j23 Mędrzec (194,920 p.)

Pytanie dlaczego używasz zmiennej d w konstruktorze kopiującym, skoro w ogóle jej nim nie ma?

Wcześniej myślałem, że to jest pole klasy, ale okazuje się, że to parametr konstruktora parametrycznego. Musisz się bardziej skupić nad tym, co robisz, bo ten wątek robi się przez takie akcje coraz bardziej chaotyczny.

komentarz 22 sierpnia 2020 przez lujasjeden Użytkownik (860 p.)

tak, przepraszam bardzo sie wciagnalem i poswiecam mnostwo czasu na c++ (dzisiaj praktycznie caly dzien) a co za tym idzie mozg mi sie przemecza ale ogolnie wszystko juz chyba dziala

 

output jakbys chcial zobaczyc zapisy kiedy co sie wywoluje:

Input degree of polynomial P(x): 3
Input coefficients and constant of polynomial P(x):
x^3: 1
x^2: 2
x^1: 3
x^0: 4
P(x)= x3+2x2+3x+4

copyWx constructor called
copyWx constructor called
Main menu
---------------------
1.Addition
2.Subtraction
3.Multiplication
4.Division
5.Exit

Choose an operation: 1
W(x)+P(x) = copyWx constructor called
copyWx constructor called
Wx destructor called
Wx destructor called
Wx destructor called
Wx destructor called
copyWx constructor called
copyWx constructor called
2x5+3x4+5x3+3x2+26x+5

Press enter

po enterach

Wx destructor called
Wx destructor called
Result destructor called
Wx destructor called
Wx destructor called
Wx constructor called
Wx constructor called
Result constructor called
Input degree of polynomial W(x):

Dzieki ogolnie za cala pomoc, ja na dzisiaj koncze jutro pewnie bede cisnal juz mnozenie i dzielenie bo sprawdzanie czy input jest floatem i intem juz mam wiec chyba narazie wszystko z takiego zabezpieczenia

komentarz 23 sierpnia 2020 przez lujasjeden Użytkownik (860 p.)

tak ogolnie to powinienem dawac kopie czy referencje tutaj:

        r.menu(w, p);
        r.showResult(w, p);

bo w sumie to po wykonaniu dzialan objekty Wx oraz Px nie sa juz uzywane i i tak sa niszczone, poza tym jest to ekonomiczniejsze posylac cale objekty, czyli wychodzilo by ze lepiej ich nie kopiowac tylko poslac cale (tutaj mialby zastosowanie move constructor??? dobrze mysle?)

 

komentarz 23 sierpnia 2020 przez j23 Mędrzec (194,920 p.)

Pisałem wcześniej, że obiekty, które są klasami prawie zawsze powinieneś przekazywać przez [const] referencję.

dobrze mysle?

Nie. Przekazywanie przez wartość to tworzenie kopii obiektu, a tworzenie niepotrzebnie kopii obiektu to pisanie nieoptymalnego kodu.

poza tym jest to ekonomiczniejsze posylac cale objekty, czyli wychodzilo by ze lepiej ich nie kopiowac tylko poslac cale

Nie bardzo rozumiem, co rozumiesz przez "posyłać całe obiekty". Nie da się wysłać pół czy ćwierć obiektu...

tutaj mialby zastosowanie move constructor?

Nie miałby. Zresztą jak to sobie wyobrażasz, skoro wywołanie menu "zabrałoby" obiekty w i p? Co dostałaby w argumentach funkcja showResult?

komentarz 23 sierpnia 2020 przez lujasjeden Użytkownik (860 p.)
r.menu(const Wx &w, const Wx/Px &p);
r.showResult(const Wx w&, const Wx/Px &p)

W ten sposób? Nie dzieje się to samo co w przypadku tym co mówiłeś że:

Zresztą jak to sobie wyobrażasz, skoro wywołanie menu "zabrałoby" obiekty w i p? Co dostałaby w argumentach funkcja showResult?

 

komentarz 23 sierpnia 2020 przez j23 Mędrzec (194,920 p.)

W ten sposób?

Co to niby jest?

Wx/Px

WTF?!

komentarz 23 sierpnia 2020 przez lujasjeden Użytkownik (860 p.)

No napisałeś:

Pisałem wcześniej, że obiekty, które są klasami prawie zawsze powinieneś przekazywać przez [const] referencję.

To myślałem że się pisze const w argumentach, a nie wiedziałem czy pisać Wx czy Px dla &p więc napisałem Wx/Px żebyś mi napisał które jest poprawne, ale po twojej odpowiedzi widzę że zupełnie nie o to ci chodzi, więc moje pytanie jak się przekazuje przez const referencje 

komentarz 23 sierpnia 2020 przez j23 Mędrzec (194,920 p.)

No przecież przekazywałeś już argumenty przez referencję! Zobacz, jak wygląda konstruktor kopiujący albo operator przypisania.

Google nie gryzie -> link

 

komentarz 23 sierpnia 2020 przez lujasjeden Użytkownik (860 p.)

W takim razie jeżeli mam nie pisać const w argumencie to zmyliło mnie to że pisałeś że mam przesyłać je przez [const] referencje. Jeżeli mam przesyłać przez referencje to ma to wyglądać po prostu w ten sposób tak:?

r.menu(&w, &p);
r.showResult(&w, &p);

Chociaż teraz patrzę to mogłoby być jeszcze tak:

r.menu(const &w, const &p);
r.showResult(const &w, const &p);

A twoje "co  to niby jest"  moglo odnosić się do tego że pisałem Wx i Pc jeszcze do tego

komentarz 23 sierpnia 2020 przez j23 Mędrzec (194,920 p.)

W takim razie jeżeli mam nie pisać const w argumencie

A gdzie ja napisałem, że masz nie pisać const? Można i tak, i tak. Na ogół przekazuje się z const, bo z reguły argumenty funkcji są read-only. Dodatkowo użycie tego kwalifikatora daje możliwość użycia wartości tymczasowych (r-wartości).

to ma to wyglądać po prostu w ten sposób tak:?

Przeczytałeś linka, którego dałem w poprzednim komentarzu?

komentarz 23 sierpnia 2020 przez lujasjeden Użytkownik (860 p.)
Tak przeczytałem i jest tam tak jak napisalem
komentarz 23 sierpnia 2020 przez j23 Mędrzec (194,920 p.)
Nie ma.

Przeczytaj jeszcze raz ze zrozumieniem. Przeanalizuj kod.
komentarz 24 sierpnia 2020 przez lujasjeden Użytkownik (860 p.)
ok jestem debilem ogolnie, ale chyba tez wzrokowcem i potrzebowalem obejrzec o tym na yt niz tylko przeczytac, ogolnie posylajac wszystko przez const referencje to nie wywola sie nigdy copy constructor tak? takto po co go definiowalem i tak samo move constructor i oba operatory
1
komentarz 24 sierpnia 2020 przez j23 Mędrzec (194,920 p.)

ogolnie posylajac wszystko przez const referencje to nie wywola sie nigdy copy constructor tak?

Tak, po to przesyłasz przez referencję, by nie kopiować.

to po co go definiowalem

Wspomniana Rule of Three/Five. Mógłbyś oczywiście dać takie deklaracje:

Result(const Result &) = delete; 
Result& operator=(const Result&) = delete; 

Wtedy obiekt klasy Result byłby niekopiowalny/nieprzenoszalny, ale zapewne w trakcie pisania programu okazałoby się, że jednak możliwość kopiowania jest potrzebna.

–1 głos
odpowiedź 19 sierpnia 2020 przez Official gildin Bywalec (2,820 p.)
Nie lepiej użyć po prostu zwykłego wskaźnika ?
komentarz 19 sierpnia 2020 przez lujasjeden Użytkownik (860 p.)
tzn? jakiego wskaznika?
komentarz 19 sierpnia 2020 przez Official gildin Bywalec (2,820 p.)
No nie wiem, na klasę?
komentarz 19 sierpnia 2020 przez lujasjeden Użytkownik (860 p.)
Prosze tlumaczyc jak dla laika, bo to pierwszy moj projekt oop i nigdy wczesniej nie uzywalem konstruktorow, destruktorow itp i troche sie w tym gubie. Co mi da uzycie wskaznika na klase (ktora?) w tej sytuacji?

Podobne pytania

0 głosów
1 odpowiedź 145 wizyt
pytanie zadane 30 marca 2020 w C i C++ przez Quegon23 Nowicjusz (150 p.)
0 głosów
1 odpowiedź 227 wizyt
pytanie zadane 7 sierpnia 2020 w C i C++ przez lujasjeden Użytkownik (860 p.)
+1 głos
2 odpowiedzi 172 wizyt
pytanie zadane 19 października 2015 w C i C++ przez Dash Nałogowiec (29,650 p.)

92,572 zapytań

141,423 odpowiedzi

319,645 komentarzy

61,959 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...