Konstruktor i destruktor z dynamiczną alokacją

Konstruktor i destruktor z dynamiczną alokacją
0

Witam.
Mam napisać program, który przy pomocy konstruktora stworzy dynamiczne pamięć a za pomocą destruktora zwolni ją.

Chciałbym Was zapytać, czy zrobiłem to dobrze:

Kopiuj
 #include <iostream>
using namespace std;

class create
{
    private:
    int *wsk;
    public:
create(int ile)
{
wsk = new int(ile);

}
~create()
{
    delete wsk; // zwalnianie pamieci
}
void view()
{
    cout << *wsk << endl;
}


};

int main()
{
    int wielk;

cout << "Podaj wielkosc obiektu, ktory chcesz stworzyc: ";
cin >> wielk;

create obj(wielk); // tworze obiekt
obj.view(); //wyswietlam
obj.~create(); // kasowanie obiektu;



}

Proszę o ewentualne uwagi...
Nie jestem pewien czy dobrze to zrobiłem:

Kopiuj
create(int ile)
{
wsk = new int(ile);

} 

Tutaj musi być ten nawias (ile) czy można to zrobić inaczej?

edytowany 1x, ostatnio: madmike
xeo545x39
  • Rejestracja:ponad 14 lat
  • Ostatnio:ponad 5 lat
  • Lokalizacja:Kosmos
  • Postów:1571
1

Zależy co chcesz zrobić. Chciałeś zarezerwować tyle pamięci ile ma parametr ile? Konstruktor int'a przyjmuje wartość jaką ma przybrać int po jego stworzeniu. Czyli linijka:

Kopiuj
wsk = new int(10);

jest poprawna z tym, że rezerwujesz dla niej 4 bajty (int) i przypisujesz wartość 10.


Co kurła debuguj ten kod i streszczaj się klientowi chce się fixa, a jak nie kurła to odpale visuala i ci pomoge a tego byś nie chciał
0

Tak, mam int przypisać. Czyli mogę tak do oddać?

xeo545x39
  • Rejestracja:ponad 14 lat
  • Ostatnio:ponad 5 lat
  • Lokalizacja:Kosmos
  • Postów:1571
0

Tak, możesz jeszcze wyzerować wskaźnik, dla ścisłości: wsk = 0;.


Co kurła debuguj ten kod i streszczaj się klientowi chce się fixa, a jak nie kurła to odpale visuala i ci pomoge a tego byś nie chciał
iooi
  • Rejestracja:ponad 14 lat
  • Ostatnio:ponad 11 lat
  • Postów:573
0

Dlaczego jawnie wywołujesz destruktor? W twoim programie obj zostanie zniszczony dwa razy.

xeo545x39
A nie jest tak, że jak sam sobie zabiję obiekt, to już dalej z nim się nic nie dzieje?
iooi
Jak alokujesz na stosie i obiekt wyjdzie z zasięgu, to masz zagwarantowane, że zostanie wywołany destruktor. Jeśli sam wywołasz go wcześniej, to masz dwa takie wywołania.
KR
  • Rejestracja:prawie 16 lat
  • Ostatnio:5 miesięcy
  • Postów:2514
0

nie ma konstruktora kopiującego, przez co wywoływany jest automatyczny..
tutaj masz coś podobnego:
http://4programmers.net/Forum/C_i_C++/190622-operator_a_przypisanie?start=10


░█░█░█░█░█░█░█░█░█░█░█░
xeo545x39
A na co mu ctor kopiujący? On ma napisać alokowanie i zwalnianie pamięci ;d
KR
po to zeby nie uczyl sie zlych nawykow
0

Tak się dzieje, że sam sie usuwa? Przecież jak dwa razy wywołam ten obiekt bez użycia destruktora to on się wypisze... a jak użyje destruktora to nie.

MasterBLB
  • Rejestracja:około 19 lat
  • Ostatnio:około 7 godzin
  • Lokalizacja:Warszawa
  • Postów:1454
0

Esencją destruktora jest fakt, że jest wywoływany automatycznie kiedy obiekt jest niszczony.


"Sugeruję wyobrazić sobie Słońce widziane z orbity Merkurego, a następnie dupę tej wielkości. W takiej właśnie dupie specjalista ma teksty o wspaniałej atmosferze, pracy pełnej wyzwań i tworzeniu innowacyjnych rozwiązań. Pracuje się po to, żeby zarabiać, a z resztą specjalista sobie poradzi we własnym zakresie, nawet jeśli firma mieści się w okopie na granicy obu Korei."
-somekind,
konkretny człowiek-konkretny przekaz :]
edytowany 2x, ostatnio: madmike
0

To kiedy mój obiekt jest niszczony, skoro ja tego destruktora nie wywołuję?

Azarien
  • Rejestracja:ponad 21 lat
  • Ostatnio:około 5 godzin
0

‌ Jeśli tworzysz obiekt na stosie (a nie na stercie czyli przez wskaźnik i new/delete), to obiekt jest niszczony w momencie, gdy „wylatuje z zasięgu”. W twoim przypadku nie trzeba wywoływać destruktora, bo i tak się wykona. Zobacz na ten przykład:

Kopiuj
        int main()
        {
              create obj(wielk); // wywołanie konstruktora create::create(int)
              obj.view(); // ok

              if (true) // jakiś warunek, dla uproszczenia — zawsze prawdziwy
              {
                      create obj2 = obj; // wywołanie konstruktora kopiującego.
                                         // jeśli takiego nie ma, wywoła się domyślny,
                                         // który skopiuje tylko wskaźnik zamiast wszystkich wskazywanych danych.
                      obj2.view(); // ok
                      obj.view();  // ok
              } // skończył się zasięg zmiennej obj2. wykona się destruktor dla obj2, a w nim delete na wskaźniku.

              obj.view(); // BUM! odwołanie do wskaźnika tego samego, który został zwolniony w destruktorze obj2.
        } // skończył się zasięg zmiennej obj, wykona się destruktor.

‌ Rozwiązaniem są:

    a) zablokowanie konstruktora kopiującego i operatora kopiowania-przypisania, czyli zadeklarowanie ich jako prywatne (i nie definiowanie ich),
Kopiuj
        private:
            create::create(const create&);
            create& operator=(const create&);
        wtedy niemożliwe staje się przypisanie obj2=obj.


    b) zdefiniowanie prawidłowych:
Kopiuj
        public:

           create(const create& other)
           {
              // kopiowanie wszystkich pól o typach prostych:
              ile = other.ile; // musisz dodać to pole do klasy i wypełniać je w konstruktorze!

              // alokacja pamięci w nowym obiekcie:
              wsk = new int(ile);

              // kopiowanie właściwych danych:
              memcpy(wsk, other.wsk, ile * sizeof(int));
           }

           create& operator=(const create &other)
           {
               if (this != &other) // zabezpieczenie przed przypisaniem do samego siebie
               {
                 ile = other.ile; // j.w.
                 wsk = new int(ile);
                 memcpy(wsk, other.wsk, ile * sizeof(int));
               }
               return *this; // bo tak.
           }

‌ Tak, jest to upierdliwe — zwłaszcza w klasach, w których często dodajesz nowe pola. Wtedy trzeba pamiętać, by je dodać do tego konstruktora i operatora. Cóż, C++ to nie jest język w którym pisze się przyjemnie.

‌ Ja w przypadku większych klas przyjmuję punkt a), czyli zabraniam kopiowania, a operuję tylko na wskaźnikach (czyli u ciebie create *obj=new create(wielk), pamiętać o delete). Wtedy mój przykład będzie wyglądał tak:

Kopiuj
        int main()
        {
              create *obj = new create(wielk); // wywołanie konstruktora create::create(int)
              obj.view(); // ok

              if (true)
              {
                      create *obj2 = obj; // tylko skopiowanie wskaźnika
                      obj2.view(); // ok
                      obj.view();  // ok
                      // delete obj2; // możemy to tu zrobić, ale nie musimy. jednak spowodowałoby to też zniszczenie obj.
              } // skończył się zasięg zmiennej obj2. nic się nie dzieje.

              obj.view(); // ok
              delete obj; // wywołanie destruktora.
        } // skończył się zasięg zmiennej obj, nic się nie dzieje (dlatego trzeba pamiętać o delete)

‌ Jak widać, w C++ obiekt albo sam się zniszczy, albo robimy to ręcznie, ale przez delete. Ręczne wywoływanie destruktora jest praktycznie niepotrzebne.

edytowany 6x, ostatnio: Azarien
ZJ
  • Rejestracja:około 14 lat
  • Ostatnio:około 12 lat
0

Gdy obiekt był na stosie, to jest niszczony jak wyjdzie z zakresu. W przypadku obiektów na stercie (alokowanych z użyciem new) destruktor wywoływany przy okazji delete.

rafal__
  • Rejestracja:ponad 18 lat
  • Ostatnio:12 miesięcy
0
Hipek napisał(a)

To kiedy mój obiekt jest niszczony, skoro ja tego destruktora nie wywołuję?

Kopiuj
void funkcja()
{
    create c1 ;

    //coś tam coś tam

    {
        create c2 ;
        //coś tam coś tam kod
    } //   <---tu jest niszczony create c2

    //coś tam kod 3

} // <---tu jest niszczony c1

mam nadzieję, że zrozumiałeś.

0

Ale nawet jak nie mam zdefiniowanego destruktora to on się w jakiś magiczny sposób wywoła czy musi on być stworzony przeze mnie?

0

Rafał, tobie chodzi o zakres to rozumiem ;) Ale ja w swoim programie nie dawałem takich ficzerów

byku_guzio
  • Rejestracja:prawie 15 lat
  • Ostatnio:około 7 lat
0

Jak nie zdefiniujesz to się nie wywoła, bo i po co? Destruktor służy do zwalniania zasobów, które nie zwolnią się automatycznie w momencie wywołania delete lub wyjścia z zasięgu obowiązywania zmiennej(jeżeli obiekt jest tworzony na stosie).

Jeżeli masz zdefiniowany destruktor to wywoła się sam automatycznie wtedy kiedy ma się wywołać - tak jak wyżej inni napisali.
Dodatkowo nigdy nie wolno wywoływać destruktora jawnie(poza jednym wyjątkiem).


0

No, a ja nie mam żadnego zasięgu więc? Wtedy mogę jawnie? Jak nie to kiedy?

byku_guzio
  • Rejestracja:prawie 15 lat
  • Ostatnio:około 7 lat
0

Masz zasięg, który się kończy razem z wyjściem z funkcji main. Jawne wywołanie destruktora może być potrzebne przy dziedziczeniu wirtualnym.


0

Czyli w takim razie nie musze destruktora wywoływać tak?
Ale mogę to zostawić w celach...dydaktycznych?

byku_guzio
  • Rejestracja:prawie 15 lat
  • Ostatnio:około 7 lat
0

Nie! Czego nie rozumiesz z: "nigdy nie wolno wywoływać destruktora jawnie(poza jednym wyjątkiem)"? Jak go wywołasz jawnie to wywoła się dwa razy i program może wylecieć w kosmos. De facto będziesz miał szczęście jak Ci się wywali, bo będziesz wiedział, że masz błąd, ale przez to może się wywalić w najmniej oczekiwanym momencie gdzieś tam kiedyś tam u kogoś tam.


edytowany 2x, ostatnio: byku_guzio
Azarien
  • Rejestracja:ponad 21 lat
  • Ostatnio:około 5 godzin
0

w celach dydaktycznych to właśnie go nie wywołuj, a może dodaj komunikaty (jakieś cout<<"destruktor"<<endl) i będziesz wiedział kiedy co się wykonuje i w jakiej kolejności.

0

Żeby dodać ten komunikat to przecież i tak muszę napisać obj.~create
czy mam po prostu z def tego konstruktora wywalic te delete i dac cout<< ??

MasterBLB
  • Rejestracja:około 19 lat
  • Ostatnio:około 7 godzin
  • Lokalizacja:Warszawa
  • Postów:1454
0

NIE.Pojmij wreszcie,że WYWOŁANIEM DESTRUKTORA W ODPOWIEDNIM MOMENCIE ZAJMUJE SIĘ SYSTEM a nie ty.


"Sugeruję wyobrazić sobie Słońce widziane z orbity Merkurego, a następnie dupę tej wielkości. W takiej właśnie dupie specjalista ma teksty o wspaniałej atmosferze, pracy pełnej wyzwań i tworzeniu innowacyjnych rozwiązań. Pracuje się po to, żeby zarabiać, a z resztą specjalista sobie poradzi we własnym zakresie, nawet jeśli firma mieści się w okopie na granicy obu Korei."
-somekind,
konkretny człowiek-konkretny przekaz :]
0
Kopiuj
 #include <iostream>
#include <ctime>
using namespace std;
void zwloka(int ile_sekund)
{
    time_t czas_poczatkowy = time(NULL);
    while(time(NULL) - czas_poczatkowy < ile_sekund);
}
class create
{
    private:
    int *wsk;
    public:
create(int ile)
{
wsk = new int(ile);

}
~create()
{
    delete wsk; // zwalnianie pamieci
    cout << "Zwolniono..." << endl;
}
void view()
{
    cout << *wsk << endl;
}


};

int main()
{
    int wielk;

cout << "Podaj wielkosc obiektu, ktory chcesz stworzyc: ";
cin >> wielk;

create obj(wielk);
cout << "Gratulacje! Stworzyl Pan nowy obiekt, o wielkosci ";
obj.view();




}

tak okej?;>

Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)