2011-11-23 11 views
18

Chciałbym sprawdzić moje zrozumienie i wnioski w tej sprawie.Mam rację mówiąc, że const_cast, po którym następuje modyfikacja na const-to-const związanej z plikiem tymczasowym, jest w porządku?


Na IRC, pytano:

Czy dopuszczalne jest const_castconst odniesienia, który jest zobowiązany do tymczasowego obiektu?

Tłumaczenie: ma const ref-to-związany tymczasowy, i chce wyrzucać jej const -ness aby go zmodyfikować.

Moją odpowiedzią było to, że poprosiliśmy a similar question poprzednio, gdzie konsensus wydawało się, że nie są sami tymczasowych natury const, a tym samym, że można zrzucić const -ness z odniesieniem trzeba je i modyfikować przez wynik. I tak długo, jak ten pierwotny ref-to-const nadal istnieje, nie wpłynie to na czas życia tymczasowego.

czyli:

int main() 
{ 
    const int& x = int(3); 

    int& y = const_cast<int&>(x); 
    y = 4; 

    cout << x; 
} 
// Output: 4 
//^Legal and safe 

mam rację?


(Oczywiście, czy taki kod jest rzeczywiście wskazane jest zupełnie inna sprawa!)

+0

@ Mark: Oh, literał mógł być złym wyborem. Stwierdziłem, że nie jest to dosłowne na to pytanie. –

+0

Już miałem powiedzieć, że nie było tymczasowych w tym kodzie. Na szczęście odświeżyłem stronę zanim to zrobiłem :) – Gorpik

+0

afaik (ale nie mogę go znaleźć w stadnardzie) mówi coś w stylu "kiedy został zadeklarowany jako const, to możesz nie odrzucić constness" ... więc pytanie jest , jest literałem zadeklarowanym jako const? Nie sądzę, ponieważ powoduje to tymczasowy obiekt, więc jest zadeklarowany jako const? Nie mam pojęcia, ale moje odwagi mówią: no – PlasmaHH

Odpowiedz

8

nr

Po pierwsze, o ile mogę powiedzieć, czy to jest dosłowne lub nie jest nieistotne. Rvalues ​​typów non-klasie mają zawsze non-cv zakwalifikowane typów (§3.10/9), jednak w §8.5.3 (inicjalizacji odniesienia), mamy:

odniesienie do typu „ CV1 T1” został zainicjowany przez wyrażenie typu «CV2 T2» w następujący sposób:

[...]

-

przeciwnym razie tymczasowa typu «CV1 T1» jest tworzony i inicjowany od wyrażenia inicjalizatora za pomocą reguł dla inicjacji kopii niebędącej odwołaniem ialization (8.5). Odniesienie jest następnie powiązane z tymczasowym. Jeśli T1 jest odniesiony do T2, cv1 musi mieć taką samą kwalifikację cv co lub większą wersję cvqualification niż cv2; w przeciwnym razie program jest źle sformułowany.

(. Wszystko z poprzednich punktów dotyczy ani lwartościami lub typy klasa)

W naszym przypadku mamy:

int const& x = ...; 

Więc CV1 T1 jest int const, a tymczasowy obiekt tworzymy ma typ int const.Jest to stała najwyższego poziomu (na obiekcie), więc każda próba modyfikacji jej jest nieokreślonym zachowaniem.

Przynajmniej, to moja interpretacja. Chciałbym, żeby standard był trochę bardziej przejrzysty.

+0

Czy to nie tylko 3.10/9 i 8.5.3 wzajemnie sprzeczne? –

+2

@ TomalakGeret'kal Niezupełnie. §3.10/9 mówi o wartościach i lwartościach. Wyrażenie takie jak '3' lub' int (3) 'jest wartością r. §8.5.3 mówi o tym, jak zainicjować referencję; referencje nigdy nie są wartościami r i muszą odnosić się do obiektu w postaci . Tak więc §8.5.3 mówi, że kompilator tworzy tymczasowy obiekt, zainicjalizowany z wartością r, i wiąże odniesienie do tego. Nie otrzymujesz odnośnika do liczby całkowitej, ponieważ takie rzeczy nie istnieją: otrzymujesz odwołanie do niewidocznego obiektu, który nie jest nazwany, a który ma typ odwołania (a nie inicjalizatora ). –

+0

Ah! Rozumiem ............... Ciekawe. Następnie zgadzam się z twoim wnioskiem, i przypuszczam, że oznacza to, że przedłużenie życia tymczasowych ma niefortunne następstwo, że nie możemy ich modyfikować. –

1

Odpowiedź zależy od sposobu utworzenia pliku tymczasowego i od zainicjowania referencji.

Jeśli jawnie utworzono tymczasowo siebie jako obiekt typu niestałego, a sytuacja gwarantuje, że odwołanie do const jest przypisane konkretnie do utworzonego tymczasowo, to można bezpiecznie odrzucić stałość odwołania i zmodyfikować obiekt.

Z drugiej strony, jeśli tymczasowy został domyślnie utworzony dla ciebie przez kompilator, to tymczasowy będzie stał. W takim przypadku modyfikacja tego tymczasowego prowadzi do UB.

Niestety, standard języka C++ sam w sobie nie wydaje się gwarantować sytuacji, w których konieczne jest pierwsze podejście inicjujące. W dowolnym kontekście kompilator może wprowadzić dodatkową tymczasową kopię oryginalnego pliku tymczasowego. Nowy tymczasowy będzie const (jak wspomniano powyżej), a zatem niemodyfikowalny. To, czy tak się dzieje, czy nie, jest zdefiniowane przez implementację, jak określono w 8.5.3/5.

W ogólnym przypadku odpowiedź brzmi "nie", podczas gdy odpowiedź specyficzna dla wdrożenia może być inna.

+0

Nie mogę znaleźć niczego w 8.5.3/5, które wskazuje, że jakiekolwiek tymczasowe na RHS _ nie mógł przejść do klauzuli James cytowane. Czy możesz wykazać, że scenariusz jest inny, gdy "jawnie utworzę tymczasowy [siebie]"? –

+1

@Tomalak Geret'kal: Cóż, dla klasy typu 'T', jeśli po prostu robię' const T & r = T() ', mam szansę, że odwołanie zostanie dołączone bezpośrednio do mojego' T() '(mówi 8.5.3/5), który nie jest const. W takim przypadku całkowicie legalne jest odrzucenie konstytutywności i modyfikacja obiektu. – AnT

+0

8.5.3/5 jest ogromny i, jak powiedziałem, nie mogę znaleźć kroków dedukcyjnych, których używasz. –