a hihetetlen Const referencia, amely nem Const

megjelent július 13, 2018 – 23 Megjegyzések

napi C++

miközben a NamedType könyvtáron dolgoztam, találkoztam egy olyan helyzettel, amely zavarba ejtett: egy const referencia, amely lehetővé teszi a hivatkozott objektum módosítását. const_castnélkül. mutable nélkül. Anélkül, hogy bármi fel a hüvely.

hogyan lehet ez? És hogyan lehet érvényesíteni a const értéket ebben a const hivatkozásban?

egy const hivatkozás, amely nem const

itt van egy leírás egy olyan helyzetről, amikor ez a furcsa hivatkozás felmerül. Vegye figyelembe a következő burkolóosztályt:

template<typename T>class Wrapper{public: Wrapper(T const& value) : value_(value) {} T const& get() const { return value_; } private: T value_;};

ez a Wrapper osztály tárolja a T típusú értéket, és hozzáférést biztosít a get() módszerrel (ettől függetlenül, ha kíváncsi vagy, hogy a “get” jó név-e, érdemes elolvasni ezt a részletes vitát). Fontos, hogy a get() metódus csak olvasható hozzáférést biztosít a tárolt értékhez, mert const hivatkozást ad vissza.

ennek ellenőrzéséhez példányosítsuk a sablont például int – vel. A tárolt érték get() metódussal történő módosítása sikertelen (próbálja meg kattintani a Futtatás gombra).

ami nagyon jó, mert azt akarjuk, hogy a get() csak olvasható legyen.

de most példányosítsuk a Wrapper – t int& – vel. Ennek egyik felhasználási módja lehet például a másolat elkerülése vagy a a lehetséges módosításainak nyomon követése. Most próbáljuk meg módosítani a tárolt értéket a get()által visszaadott const hivatkozáson keresztül:

és ha megnyomod a gombot, látni fogod, hogy… összeáll! És kiírja a const hivatkozáson keresztül módosított értéket, mintha semmi különös nem történt volna.

hát nem érthetetlen? Nem érzi, hogy a const által nyújtott biztonság megnyugtató benyomása összeomlik körülöttünk? Kiben bízhatunk?

próbáljuk megérteni, mi történik ezzel a hivatkozással.

Const hivatkozás vagy hivatkozás a const-ra?

a lényeg az, hogy az a referenciánk egy const referencia, de nem hivatkozás a const-ra.

hogy aláhúzzuk, mit jelent ez, bontsuk le lépésről lépésre, mi történik a sablon példányában.

a get() metódus const T& értéket ad vissza, a Ta template T – ből származik. Második esetünkben a T int&, tehát a const T&const (int&) &.

nézzük meg közelebbről ezt a const (int&) – et. A int& egy hivatkozás, amely int – re utal, és módosíthatja azt a int – et. De a const (int&) egy int& hivatkozás, azaz const, ami azt jelenti, hogy maga a hivatkozás nem módosítható.

mit jelent egy hivatkozás módosítása? Elméletileg azt jelentené, hogy egy másik tárgyra utal, vagy nem utal semmire. De mindkét lehetőség illegális A C++ – ban: a referencia nem tud újracsatolni. Ugyanarra a tárgyra utal az egész élete során.

tehát a const nem sokat mond referenciaként, mivel mindig const, mivel nem tudnak újracsatolni. Ez azt jelenti, hogy a const (int&)gyakorlatilag ugyanolyan típusú, mint a int&.

ami azt jelenti, hogy get()visszatér (int&) &. A referenciák szabályai szerint ez int&.

tehát a getegy int& értéket ad vissza. A kezelőfelülete T const&, de valójában int&. Nem igazán kifejező kód, ugye?

hogyan lehet a const hivatkozást hivatkozássá tenni a const-ra

most, hogy már túl vagyunk a probléma megértésének első lépésén, hogyan javíthatjuk meg? Vagyis hogyan tehetjük vissza a get() hivatkozást a tárolt értékre, amely nem teszi lehetővé annak módosítását?

ennek egyik módja a const kifejezett beszúrása a hivatkozásba. Ezt úgy tehetjük meg, hogy levesszük a hivatkozást, hozzáadunk egy const értéket, és visszahelyezzük a hivatkozást. A hivatkozás eltávolításához a std::remove_reference – et használjuk a C++11-ben, vagy a kényelmesebb std::remove_reference_t – t a C-ben++14:

amint láthatja, ha a Futtatás gombra kattint, a várható fordítási hiba Most megjelenik, amikor megpróbálja módosítani a Wrapper – ben tárolt értéket.

azt hiszem, hasznos megérteni, hogy mi történik ezzel a hivatkozással, mert ez a kód úgy néz ki, mintha biztonságos lenne, de valójában nem, és ez a legveszélyesebb fajta.

az oldalba ágyazott fenti játszóterek kódjával játszhatsz. Nagy köszönet a rakete1111 stack overflow felhasználónak, hogy segített megérteni a probléma okait.

Ön is kedvelheti

  • a leginkább bosszantó elemzés: hogyan lehet észrevenni és gyorsan megjavítani

Vélemény, hozzászólás?

Az e-mail-címet nem tesszük közzé.