Destruktor - samoczynne odpalanie

Destruktor - samoczynne odpalanie
Adamos19
  • Rejestracja:ponad 10 lat
  • Ostatnio:ponad 2 lata
  • Postów:293
0

Ok. Ale to dlaczego taki kod również powoduje wycieki:

Kopiuj
	std::vector<Punkt3D> v;

	while (1)
	{
		v.push_back(*(new Punkt3D(1, 2, 3)));
		v.clear();
	}
kq
Moderator C/C++
  • Rejestracja:prawie 12 lat
  • Ostatnio:około 16 godzin
  • Lokalizacja:Szczecin
1

Bo nie zwaliniasz pamięci zaalokowanej przez new.


Adamos19
  • Rejestracja:ponad 10 lat
  • Ostatnio:ponad 2 lata
  • Postów:293
0

No dobrze, rozumiem. Ale czy to znaczy że w przypadku gdy robię:

Kopiuj
		v.push_back(*(new Punkt3D(1, 2, 3)));

obiekt wektor robi kopię tego mojego Punkt3D i tą właśnie kopię sobie zachowuje?
I czy to również oznacza że jeśli zrobię tak:

Kopiuj
	std::vector<Punkt3D> v;

	for (int i = 0; i < 10; i++)
	{
		Punkt3D * temp = new Punkt3D(1, 2, 3);
		v.push_back(*temp);
		delete temp;
	}

to wektor będzie trzymać mi te 10 punktów pomimo że je skasowałem?

kq
Moderator C/C++
  • Rejestracja:prawie 12 lat
  • Ostatnio:około 16 godzin
  • Lokalizacja:Szczecin
0

Tak, wektor będzie miał kopie tych punktów. Zapewne już ten link widziałeś, ale: https://dsp.krzaq.cc/post/176/ucze-sie-cxx-kiedy-uzywac-new-i-delete/


Adamos19
Drobna sprawa. Czy możesz potwierdzić że w przypadku gdy dochodzi do kopiowania tego punktu (celem umieszczenia go w kolekcji) to system wywołuje konstruktor kopiujący zaimplementowany (jawnie bądź niejawnie) w klasie Punkt3D ?
kq
Potwierdzam
Adamos19
  • Rejestracja:ponad 10 lat
  • Ostatnio:ponad 2 lata
  • Postów:293
0

Szczerze? Chciałbym to przeczytać po raz czwarty, bo jak czytam po raz kolejny to rozumiem coraz więcej... Ale nie mam na wszystko czasu... Chciałbym aby dzień trwał nie 24 ale przynajmniej 36 h. :) Ale mimo wszystko dzięki. Może jutro, w Święto znajdę trochę czasu na kolejne przeczytanie i dokładną analizę.

Pozdrawiam i dzięki!

Ale chciałem może jeszcze na koniec dnia zapytać:
Jak przerobić ten kod :

Kopiuj
    std::vector<Punkt3D> v;
 
    for (int i = 0; i < 10; i++)
    {
        Punkt3D * temp = new Punkt3D(1, 2, 3);
        v.push_back(*temp);
        delete temp;
    }

Aby wyeliminować konieczność zastosowania instrukcji new i delete. da jakoś radę?

edytowany 1x, ostatnio: Adamos19
enedil
  • Rejestracja:prawie 12 lat
  • Ostatnio:około 2 godziny
  • Postów:1027
2
Kopiuj
Punkt3D temp(1, 2, 3);
v.push_back(temp);
edytowany 1x, ostatnio: enedil
06
lub prościej v.emplace_back(1, 2, 3);
Adamos19
Czy w takim wypadku jedynym pozostałym obiektem po wykonaniu tej instrukcji będzie ten który trzymany jest w tej kolekcji?
Adamos19
  • Rejestracja:ponad 10 lat
  • Ostatnio:ponad 2 lata
  • Postów:293
0

Panowie, po stokroć dzięki.
Wszystko jasne już.

Panowie, ostatnie pytanie. Załóżmy że mam:

Kopiuj
Punkt3D x(1,2,3);

a następnie robię:

Kopiuj
Punkt3D y = x;

Czy wywoła się konstruktor kopiujący zakładając że nie mam przeładowanego operatora przypisania =
I czy nie wywoła się ten konstruktor jeśli mam przeładowany operator przypisania?

kq
Moderator C/C++
  • Rejestracja:prawie 12 lat
  • Ostatnio:około 16 godzin
  • Lokalizacja:Szczecin
1

Tu nie masz przypisania, więc niezależnie od definicji lub jej braku, operator przypisania na pewno nie zostanie odpalony (chyba, że zostanie gdzieś wywołany wewnątrz konstruktora kopiującego).


Adamos19
  • Rejestracja:ponad 10 lat
  • Ostatnio:ponad 2 lata
  • Postów:293
0

Załóżmy że w klasie Punkt3D mam zdefiniowany konstruktor kopiujący + dodatkowo przeładowany operator przypisania =.
Czy możecie potwierdzić że w przypadku gdy do zmiennej przypisuję obiekt po raz pierwszy (jak wyżej w kodzie który zaproponowałem) to rusza konstruktor kopiujący, a w przypadku gdy przypisuję coś ponownie to nie ruszy konstruktor kopiujący tylko ruszy przeładowany operator przypisania =.

Innymi słowy , czy możecie potwierdzić że w przypadku:

Kopiuj
Punkt3D x(1,2,3);
Punkt3D y(2,3,4);
Punkt3D z = x;
Punkt3D z = y;

wpierw (przedostatnia instrukcja) ruszy konstruktor kopiujący a potem (ostatnia instrukcja) ruszy kod przeładowanego operatora przypisania?

edytowany 1x, ostatnio: Adamos19
kq
Moderator C/C++
  • Rejestracja:prawie 12 lat
  • Ostatnio:około 16 godzin
  • Lokalizacja:Szczecin
1

Bo to jest definicja zmiennej, a nie przypisanie. Semantycznie poniższe są dokładnie tym samym:

Kopiuj
Punkt3D y = x;
Punkt3D y{x};
Punkt3D y(x); // pomijając różnice z std::initializer_list
Punkt3D y = {x};

Tak działa C++, możesz uznać to za nielogiczne, ale i tak będziesz musiał się przyzwyczaić ;​)


Adamos19
  • Rejestracja:ponad 10 lat
  • Ostatnio:ponad 2 lata
  • Postów:293
0

Ok, jestem w stanie to łyknąć. Ale napisz w takim razie przykład instrukcji przypisania i napisz swoimi słowami czym w takim razie jest przypisanie w języku C++ i jak je odróżnić od definicji o której piszesz?

kq
Moderator C/C++
  • Rejestracja:prawie 12 lat
  • Ostatnio:około 16 godzin
  • Lokalizacja:Szczecin
0

Definicja nowej zmiennej nie ma przypisania. Możesz przypisać do już istniejącej.

Kopiuj
Punkt3D x = y; // definicja z inicjalizacją
x = y; // przypisanie

Adamos19
  • Rejestracja:ponad 10 lat
  • Ostatnio:ponad 2 lata
  • Postów:293
0

Aha. Rozumiem.
Mam jeszcze dwa pytania w takim razie jeśli oczywiście pozwolisz.

Kopiuj
Punkt3D x;
x = y;

Czy powyższe jest przypisaniem?
I czy pierwsza instrukcja inicjalizuje obiekt jeśli w klasie zdefiniowany jest konstruktor bezargumentowy?

edytowany 1x, ostatnio: Adamos19
kq
Moderator C/C++
  • Rejestracja:prawie 12 lat
  • Ostatnio:około 16 godzin
  • Lokalizacja:Szczecin
1

Tak i tak.


edytowany 1x, ostatnio: kq
Adamos19
  • Rejestracja:ponad 10 lat
  • Ostatnio:ponad 2 lata
  • Postów:293
0

Po stokroć dziękuję. Wszystko jasne. Miłego wieczoru życzę.

Adamos19
  • Rejestracja:ponad 10 lat
  • Ostatnio:ponad 2 lata
  • Postów:293
0

Jedna rzecz jeszcze mi nie daje spokoju. Załóżmy przez chwilę że mam super fajnie napisana klasę CLista i załóżmy że jestem na etapie uzupełniania kodu o przeładowanie operatora przypisania właśnie. Czy dobrą myślą byłoby takie jego przeładowanie aby:

  • kasował starą listę (wszystkie jej bufory)
  • tworzył nowe bufory i przypisywał do nich to co znajduje się w obiekcie przypisywanym do tej listy

Jeśli dobrze rozumuję to takie czyszczenie o którym piszę w punkcie pierwszym musiałbym zrobić ponieważ mogłoby się okazać że stworzę nowe bufory, zapiszę do nich to co potrzeba ale stare zostaną i automatycznie mam wyciek. Czy mógłby mi ktoś potwierdzić moje wątpliwości?

I na koniec jeszcze taka sprawa. Załóżmy że mam do czynienia z przeładowywaniem operatora przypisania w dwóch wersjach:

Kopiuj
CLista & operator = (  CLista & L1, CLista & L2);
CLista & operator = (const  CLista & L);

Natknąłem się na to w internecie już nie pierwszy raz. Nie rozumiem jakim cudem pierwsza wersja może istnieć jako dwuargumentowa. Przecież to co się przypisuje to jeden argument a nie dwa...
Innymi słowy , gdzie wykorzystujemy taką formułę dwuargumentową w kontekście operatora przypisania (i chyba wielu innych bo to nie dotyczy tylko przypisania) ?

edytowany 1x, ostatnio: Adamos19
kq
Moderator C/C++
  • Rejestracja:prawie 12 lat
  • Ostatnio:około 16 godzin
  • Lokalizacja:Szczecin
0

Jeśli używasz RAII i rule of zero, to nie musisz się o nic martwić. W przeciwnym wypadku, jeśli używasz rule of three/five to musisz poprawnie zaimplementować odpowiednie operatory i konstruktory, co może wiązać się ze zwolnieniem starych zasobów.


Adamos19
  • Rejestracja:ponad 10 lat
  • Ostatnio:ponad 2 lata
  • Postów:293
0

Aktualnie nie rozumiem Twojej wypowiedzi co nie oznacza wcale że nie czytałem o rule of zero oraz o rule of three/five...
Jest to dla mnie nowość i trochę zamotany w tym jestem jeszcze...
Nie rozumiem co to jest RAII ale pojmuję że zasady rule of three/five (nie rule of zero) dotyczą dobrej praktyki programistycznej tak aby być w zgodzie z zasadami i aby w przyszłości kod który stworzymy nie spowodował przypadkiem że dojdzie do pomyłek i np. wycieków. Jednakże nie rozumiem tego co oznacza RAII i nie mogę sobie jeszcze wyobrazić sytuacji w której przy niezastosowaniu tych reguł dojdzie do pomyłek... A co do zasady rule of zero to także nie rozumiem co ona mówi.

Czytałem na szybko na razie z uwagi na brak czasu, więc albo będę to studiował tracąc swój cenny czas albo powiecie inteligentnemu facetowi kawę na ławę opisowo o co chodzi...

Poza tym prosiłbym o odniesienie się także do pytania o operatory...

kq
Moderator C/C++
  • Rejestracja:prawie 12 lat
  • Ostatnio:około 16 godzin
  • Lokalizacja:Szczecin
0

RAII jest ściśle związane z rule of 3/5/0. Generalnei chodzi o to, że jeśli masz w klasie tylko obiekty przestrzegające tych reguł, to nie musisz się nimi przejmować, bo same zajmą się swoimi zasobami. Wobec czego, w idealnym przypadku nie musisz nawet nawet definiować własnych operatorów. Za przykład takiej klasy możesz wziąć std::string. Czy zastanawiałeś się kiedyś w jaki sposób zwolnić przypisane do niego zasoby? Mam nadzieję, że nie ;​), bo on zajmuje się tym sam. Tak samo, jeśli masz klasę, której elementem jest string, to też nie ma potrzeby abyś się tym przejmował, nawet jeśli sobie go nadpisujesz.

Co do operatorów, to może to ci pomoże: https://dsp.krzaq.cc/post/304/jak-przeladowywac-operatory-w-mojej-klasie/
W skrócie: to jest ten sam operator (pomijając brak const), tylko jeden jest deklaracją wewnątrz klasy, czyli z niejawnym parametrem this, a drugi poza klasą. Oba mają swoje zastosowania, chociaż dla mnie mógłby zostać wyłącznie ten pierwszy.


Adamos19
  • Rejestracja:ponad 10 lat
  • Ostatnio:ponad 2 lata
  • Postów:293
0

Przeczytałem ze zrozumieniem zasady rule 5/3/0. Mam pytanie : dlaczego dla niektórych klas rekomenduje się zasadę rule of three a dla niektórych rule of five. Wiem że zostało to tam także wyjaśnione ale nie rozumiem sensu zasady rule of five jeśli przecież rule of three w zupełności nam wystarcza nawet gdy klasa zarządza wskaźnikami na bufory. I czy racją jest że jeśli klasa nie zarządza wskaźnikami na bufory to wówczas należy opierać się o zasadę rule of zero i niczego nie implementować własnoręcznie?

edytowany 1x, ostatnio: Adamos19
MarekR22
Moderator C/C++
  • Rejestracja:około 17 lat
  • Ostatnio:2 minuty
1

"rule of zero" używasz wtedy, kiedy twój kod nie zarządza bezpośrednio żadnymi zasobami. Np jeśli klasa nie zawiera surowych wskaźników.
Jeśli kod klasy zarządza jakimiś zasobami (np używa operatora new) to wtedy obowiązuje "rule of tree", a w C++11 preferowana jest zasada "rule of five".

Jeśli zrezygnujesz z samodzielnie alokowanej tablicy, na rzecz std::vector to wtedy "rule of zero" jest twoim przyjacielem.


Jeśli chcesz pomocy, NIE pisz na priva, ale zadaj dobre pytanie na forum.
edytowany 1x, ostatnio: MarekR22
Adamos19
  • Rejestracja:ponad 10 lat
  • Ostatnio:ponad 2 lata
  • Postów:293
0

Idealnie. Dzięki. :)

Panowie, jeszcze jedno. Co to jest konstruktor przenoszący i kiedy ma on zastosowanie? Zauważyłem że zasada rule of five ma bowiem coś wspólnego właśnie z konstruktorem przenoszącym.
Jak na razie mam problem w zrozumieniu po co taki konstruktor zdefiniowali twórcy języka?
Zakładając że klasa zarządza zasobami, to dlaczego kolega w poprzednim poście napisał że rule of five tworzymy tylko jeśli pracujemy w standardzie C++11, inaczej: co ten standard takiego za sobą niesie że dochodzą do trzech reguł dodatkowe dwie (że z rule of three robi się rule of five) ?

edytowany 1x, ostatnio: flowCRANE
kq
Moderator C/C++
  • Rejestracja:prawie 12 lat
  • Ostatnio:około 16 godzin
  • Lokalizacja:Szczecin
0

Tworzenie/alokowanie nowego zasobu jest kosztowne. Jeśli stary idzie w zapomnienie i zostanie usunięty, np. jak tutaj:

Kopiuj
vector<int> make_foo();

int main() {
    auto foo = make_foo();
}

To można, zamiast tworzyć nowy wektor i kopiować do niego dane z tego, który zaraz ma zostać usunięty, po prostu "ukraść" zawartość starego wektora. Dzięki temu unikniemy tutaj zbędnej kopii. Traktuj to konceptualnie, bo tutaj jeszcze w grę wchodzi RVO i NRVO.


Adamos19
I co to "RVO i NRVO" ??
kq
(Named) Return Value Optimization
Adamos19
  • Rejestracja:ponad 10 lat
  • Ostatnio:ponad 2 lata
  • Postów:293
0

Aha. Napisz coś jeszcze może... ;) Wiedz o tym że za wszystko co piszesz jestem Ci ogromnie wdzięczny i ogromnie rad z tego :) Dodatkowo mój przekaz do studentów których nauczam programowania jest również cenniejszy i wiedz o tym że mocno przyczyniasz się nie tyle do mojego sukcesu zawodowego (chociaż jestem automatykiem) to również dla ojczyzny ponieważ poziom wiedzy studentów których nauczam będzie inny - lepszy.
Po stokroć dzięki.

kq
Moderator C/C++
  • Rejestracja:prawie 12 lat
  • Ostatnio:około 16 godzin
  • Lokalizacja:Szczecin
1

W Programiście (60) jest mój cały artykuł o Rule of Zero, wraz z przykładami ;​) Zobaczę czy mogę wrzucić na bloga, ale jak masz do niego dostęp to, no cóż, polecam.


Adamos19
  • Rejestracja:ponad 10 lat
  • Ostatnio:ponad 2 lata
  • Postów:293
0

Dzięki, czytałem przed chwilą artykuł (znalazłem w necie). Ale jeszcze raz powtarzam to co napisałem : rule of zero i rule of three są dla mnie ZROZUMIAŁE :)
Ja chciałem się coś dowiedzieć więcej na temat rule of five... to co kazałeś mi potraktować jako "konceptualne" jest tym czego oczekuję, z tym że chciałbym coś więcej w tej materii...
Ale zaznaczam - chodzi mi o to aby wyjaśnić bardziej powiązanie standardu C++11 i rule of five... oraz istoty konstruktora przenoszącego... oraz powiązanie go z teorią dot. rule of five...

kq
Moderator C/C++
  • Rejestracja:prawie 12 lat
  • Ostatnio:około 16 godzin
  • Lokalizacja:Szczecin
0

No dobra, to jest zaledwie poruszone w tym arcie, ale w bibliografii powinien być do wpisu Scotta Meyersa na ten temat: http://scottmeyers.blogspot.com/2014/03/a-concern-about-rule-of-zero.html oraz do prelekcji Howarda Hinnanta, z której jest tabelka opisujące automatyczne tworzenie konstruktorów:

Z jednym i drugim się zapoznaj, powinno pomóc :​)


Adamos19
  • Rejestracja:ponad 10 lat
  • Ostatnio:ponad 2 lata
  • Postów:293
0

Pomogło, dzięki.
Panowie, mam jeszcze jedno pytanie. Załóżmy że mam funkcję zwracającą referencję do obiektu a w tej funkcji tworze ten obiekt jako nowy obiekt na stosie i właśnie do niego referencję zwracam.
Czy to dobra konstrukcja czy też może zła ponieważ ten obiekt (zwinięty ze stosu w chwili zakończenia funkcji) przestaje istnieć?
Do czego w takim układzie odnosi się ta referencja zwrócona przez funkcję?

Co by się stało gdybym z poziomu programu głównego (nie tej funkcji) przepisał wartość zwróconą przez tą funkcję (referencję) do innej zmiennej tego typu, czy takie coś ma sens czy również nie ma ponieważ jako że ten obiekt już nie istnieje to przepisywałyby się potocznie mówiąc śmieci ?

kq
Moderator C/C++
  • Rejestracja:prawie 12 lat
  • Ostatnio:około 16 godzin
  • Lokalizacja:Szczecin
0

Użycie referencji do nieistniejącego obiektu to UB.


AL
  • Rejestracja:prawie 11 lat
  • Ostatnio:około 3 lata
  • Postów:1493
0

@Adamos19: odnośnie move a copy: weź sobie std::auto_ptr i zobacz co się stanie kiedy spróbujesz go skopiować: oryginał zostanie wyzerowany i nie będzie już używalny. Czy jest to intuicyjne zachowanie dla kopiowania?
A teraz weź std::unique_ptr i zaobserwuj, że go nie skopiujesz. Ale jego przeniesienie da podobny efekt jak kiedyś kopiowanie auto_ptra.

Adamos19
Tak, rozumiem po co te wskaźniki są, czytałem o tym. Ale nie rozumiem jakie to ma znaczenie dla naszego problemu, dlaczego o tym piszesz teraz? Kawę na ławę prosiłbym bo pionek jestem.

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.