std::unique_ptr i wirtualny destruktor

W tym miejscu zadajemy pytania na temat języka C++, dzielimy się swoją wiedzą, udzielamy wsparcia, rozwiązujemy problemy programistyczne.
kijas1
Posty: 10
Rejestracja: sobota 02 sty 2016, 18:50

std::unique_ptr i wirtualny destruktor

Postautor: kijas1 » środa 20 sty 2016, 20:50

Witam, czy dla std::unique_ptr wymagany jest wirtualny destruktor jeśli mamy klasy pochodne? Dla zwykłego wskaźnika na klasę bazową otrzymuje ostrzeżenie, że go nie posiadam, a dla std::unique_ptr już nie, choć też powinno być, skoro wskazuje na klasę bazową.

Awatar użytkownika
mokrowski
User
User
Posty: 190
Rejestracja: czwartek 08 paź 2015, 20:50
Lokalizacja: Tam gdzie Centymetro

Re: std::unique_ptr i wirtualny destruktor

Postautor: mokrowski » czwartek 21 sty 2016, 10:07

http://en.cppreference.com/w/cpp/memory/unique_ptr

If T is a derived class of some base B, then std::unique_ptr<T> is implicitly convertible to std::unique_ptr<B>. The default deleter of the resulting std::unique_ptr<B> will use operator delete for B, leading to undefined behavior unless the destructor of B is virtual. Note that std::shared_ptr behaves differently: std::shared_ptr<B> will use the operator delete for the type T and the owned object will be deleted correctly even if the destructor of B is not virtual.


Dla porządku:
Jak nie dodasz virtual dla destruktora klasy bazowej, to tak w 1 (dostęp przez wskaźnik) jak i w 2 przypadku (dostęp przez unique_ptr), masz zachowanie niezdefiniowane UB (ang. Undefined Behavior). Dla dostępu przez unique_ptr, kompilator nie zgłasza ostrzeżenia bo domyślny destruktor który występuje w szablonie unique_ptr, zapisany jest w plikach nagłówków systemowych. Jeśli chcesz by zgłaszał, dodaj do ostrzeżeń -Wsystem-headers. Informacja o braku virutal będzie jednym z ostrzeżeń.

Kod: Zaznacz cały

#include <memory>
#include <iostream>

struct Bazowa {
  virtual void przywitaj() {
      std::cout << "z klasy bazowej\n";
  }
};

struct Pochodna : public Bazowa {
  virtual void przywitaj() override {
      std::cout << "z klasy pochodnej\n";
  }
};

int main() {
    // Przypadek 1 ze wskaźnikiem.
    Bazowa *b = new Pochodna;
    b->przywitaj();
    delete b;

    // Przypadek 2 z unique_ptr
    std::unique_ptr<Bazowa> sb = std::make_unique<Pochodna>();
    sb->przywitaj();
}


Kompilacja:

Kod: Zaznacz cały

g++ -Wall -Wextra -std=c++14 -o plik plik.cpp


Ostrzeżenie:

Kod: Zaznacz cały

plik.cpp: In function 'int main()':
plik.cpp:20:12: warning: deleting object of polymorphic class type 'Bazowa' which has non-virtual destructor might cause undefined behaviour [-Wdelete-non-virtual-dtor]
     delete b;


Kompilacja:

Kod: Zaznacz cały

g++ -Wall -Wextra -Wsystem-headers -std=c++14 -o plik plik.cpp


Ostrzeżenia (większość to o deprecated auto_ptr):
I

Kod: Zaznacz cały

n file included from /opt/local/include/gcc5/c++/memory:81:0,
                 from plik.cpp:1:
/opt/local/include/gcc5/c++/bits/unique_ptr.h: In instantiation of 'void std::default_delete<_Tp>::operator()(_Tp*) const [with _Tp = Pochodna]':
/opt/local/include/gcc5/c++/bits/unique_ptr.h:236:17:   required from 'std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp = Pochodna; _Dp = std::default_delete<Pochodna>]'
plik.cpp:23:61:   required from here
/opt/local/include/gcc5/c++/bits/unique_ptr.h:76:2: warning: deleting object of polymorphic class type 'Pochodna' which has non-virtual destructor might cause undefined behaviour [-Wdelete-non-virtual-dtor]
  delete __ptr;
  ^
/opt/local/include/gcc5/c++/bits/unique_ptr.h: In instantiation of 'void std::default_delete<_Tp>::operator()(_Tp*) const [with _Tp = Bazowa]':
/opt/local/include/gcc5/c++/bits/unique_ptr.h:236:17:   required from 'std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp = Bazowa; _Dp = std::default_delete<Bazowa>]'
plik.cpp:23:61:   required from here
/opt/local/include/gcc5/c++/bits/unique_ptr.h:76:2: warning: deleting object of polymorphic class type 'Bazowa' which has non-virtual destructor might cause undefined behaviour [-Wdelete-non-virtual-dtor]
,,Myślenie nie jest łatwe, ale można się do niego przyzwyczaić" - Alan Alexander Milne: Kubuś Puchatek

kijas1
Posty: 10
Rejestracja: sobota 02 sty 2016, 18:50

Re: std::unique_ptr i wirtualny destruktor

Postautor: kijas1 » czwartek 21 sty 2016, 10:13

Dzięki, wątpliwości rozwiane :)


Wróć do „Pisanie programów w C++”

Kto jest online

Użytkownicy przeglądający to forum: Obecnie na forum nie ma żadnego zarejestrowanego użytkownika i 3 gości