Usuwanie wskaźnika do const (T const *)

89

Mam podstawowe pytanie dotyczące wskaźników const. Nie wolno mi wywoływać funkcji niebędących składowymi stałymi przy użyciu wskaźnika do stałej. Jednak mogę to zrobić na wskaźniku const:

delete p;

Spowoduje to wywołanie destruktora klasy, która w istocie jest „metodą” inną niż stała. Dlaczego jest to dozwolone? Czy to tylko w celu wsparcia tego:

delete this;

Czy jest jakiś inny powód?

Naveen
źródło

Odpowiedzi:

112

Ma wspierać:

// dynamically create object that cannot be changed
const Foo * f = new Foo;

// use const member functions here

// delete it
delete f;

Pamiętaj jednak, że problem nie ogranicza się do dynamicznie tworzonych obiektów:

{
 const Foo f;
 // use it
} // destructor called here

Gdyby nie można było wywołać destruktorów na obiektach stałych, nie moglibyśmy w ogóle używać tych obiektów.

Agnel Kurian
źródło
21
+1 dla ostatniej zmiany. Myślę, że to prawdziwy powód. Automatyczne wywołanie destruktora dla obiektu const - prawie to samo, co delete f; gdzie f - wskaźnik na const.
bayda,
const Foo * flub Foo const * fnie jest wskaźnikiem stałej do Foo. To jest poiner do const Foo. Foo * const f jest wskaźnikiem do stałej Foo.
user11373693
48

Ujmując to w ten sposób - gdyby nie było to dozwolone, nie byłoby możliwości usunięcia obiektów const bez użycia const_cast.

Semantycznie const jest wskazaniem, że obiekt powinien być niezmienny. Nie oznacza to jednak, że obiekt nie powinien zostać usunięty.

PaulJWilliams
źródło
3
Niszczyciele potrafią mutować obiekty w dość gwałtowny sposób, więc to musi być jakieś dziwne użycie słowa „niezmienny”, o którym wcześniej nie wiedziałem ...
DarthGizka
1
@DarthGizka nie, destruktory przenoszą cię ze stanu, w którym znajduje się obiekt, do stanu, w którym go nie ma. C ++ nie definiuje żadnej metody obserwacji „mutacji” po zniszczeniu
Caleth,
@ Caleth: norma może nie pozwalać na oglądanie obiektu po zakończeniu działania jego destruktora, ale z pewnością możesz przyjrzeć się efektom ubocznym spowodowanym zniszczeniem. Stąd okoliczności mogą być łatwo zaaranżowane tak, aby mutacja „niezmiennego” obiektu była obserwowalna. W Stanach Zjednoczonych morderstwo jest trudne do ścigania, gdy nie ma ciała, ale nadal jest to morderstwo (i mogą istnieć inne dowody wystarczające do skazania). Ta sama różnica.
DarthGizka
6

Nie wolno mi wywoływać funkcji niebędących składowymi stałymi przy użyciu wskaźnika do stałej.

Tak, jesteś.

class Foo
{
public:
  void aNonConstMemberFunction();
};

Foo* const aConstPointer = new Foo;
aConstPointer->aNonConstMemberFunction(); // legal

const Foo* aPointerToConst = new Foo;
aPointerToConst->aNonConstMemberFunction(); // illegal

Pomyliłeś wskaźnik do stałej obiektu, który nie jest stałym obiektem, ze wskaźnikiem niebędącym stałym obiektem.

Powiedziawszy to,

delete aConstPointer; // legal
delete aPointerToConst; // legal

usunięcie również jest legalne z powodów podanych już w innych odpowiedziach tutaj.

Oktalist
źródło
5

Konstruktorów i Destruktorów nie należy postrzegać jako „metod”. Są to specjalne konstrukcje służące do inicjalizacji i niszczenia obiektu klasy.

„const pointer” ma wskazywać, że stan obiektu nie ulegnie zmianie, gdy wykonywane są na nim operacje, gdy jest on żywy.

Indy9000
źródło
5

Inny sposób spojrzenia na to: dokładne znaczenie wskaźnika const jest takie, że nie będziesz w stanie dokonać zmian w wskazanym obiekcie, który byłby widoczny przez ten lub inny wskaźnik lub odniesienie do tego samego obiektu. Ale kiedy obiekt ulega zniszczeniu, wszystkie inne wskaźniki na adres poprzednio zajmowany przez teraz usunięty obiekt nie są już wskaźnikami do tego obiektu . Przechowują ten sam adres, ale ten adres nie jest już adresem żadnego obiektu (w rzeczywistości może wkrótce zostać ponownie użyty jako adres innego obiektu).

To rozróżnienie byłoby bardziej oczywiste, gdyby wskaźniki w C ++ zachowywały się jak słabe referencje, tj. Gdy tylko obiekt zostanie zniszczony, wszystkie istniejące wskaźniki do niego zostaną natychmiast ustawione na 0. (Tego rodzaju rzeczy uważane są za zbyt kosztowne w czasie wykonywania, aby narzucać je wszystkim programom C ++ i w rzeczywistości nie można uczynić ich całkowicie niezawodnymi.)

AKTUALIZACJA : Czytając to dziewięć lat później, jest to prawnicze. Teraz uważam, że twoja pierwotna reakcja jest zrozumiała. Niedopuszczenie do mutacji, ale pozwolenie na zniszczenie, jest oczywiście problematyczne. Implikowana umowa wskaźników / odwołań do stałych jest taka, że ​​ich istnienie będzie działać jak blokada zniszczenia obiektu docelowego, czyli automatyczne usuwanie elementów bezużytecznych.

Zwykłym rozwiązaniem tego problemu jest użycie prawie każdego innego języka.

Daniel Earwicker
źródło
Jeśli nie możesz zniszczyć rzeczy wskazywanych przez wskaźniki const, jak sobie radzisz z std::unique_ptr<const T>zakończeniem, to jest życie?
Caleth,
@Caleth nie byłoby rozwiązania tego problemu w C ++. To tylko jeden przykład ogólnego problemu: w C ++ modyfikator const oznacza „Nie możesz zmutować celu, z wyjątkiem jednego przypadku, gdy możesz go całkowicie zniszczyć i unieważnić wszystkie inne odniesienia do niego i źródła niezdefiniowanego zachowania”. Dlatego uważam, że tego rodzaju pytania powinny zachęcić do rozważenia innych języków. Ma w sobie dziury UB, których nie można rozwiązać bez przyjęcia innego podstawowego podejścia.
Daniel Earwicker,