The Incredible Const Reference That Isn’ t Const
työskennellessäni NamedType-kirjastossa törmäsin tilanteeseen, joka jätti minut hämmästymään: const-viittaus, joka mahdollistaa sen kohteen muokkaamisen, johon se viittaa. Ilman const_cast
. Ilman mutable
. Ilman mitään hihassa.
miten tämä on mahdollista? Ja miten valvoa const
että const viittaus?
konst-viittaus, joka ei ole konst
tässä on kuvaus tilanteesta, jossa tämä outo viittaus tulee esiin. Harkitse seuraavaa kääreluokkaa:
template<typename T>class Wrapper{public: Wrapper(T const& value) : value_(value) {} T const& get() const { return value_; } private: T value_;};
tämä Wrapper
luokka tallentaa arvon tyyppi T
, ja antaa siihen pääsyn get()
– menetelmän kautta (tästä riippumatta, jos mietit, onko ” get ” hyvä nimi, kannattaa lukea tämä yksityiskohtainen keskustelu). Tärkeää on, että get()
– menetelmä antaa vain lukuoikeuden tallennettuun arvoon, koska se palauttaa konst-referenssin.
sen tarkistamiseksi instantioidaan esimerkiksi malli int
. Tallennetun arvon muokkaaminen get()
– menetelmällä ei onnistu (yritä klikata alla olevaa Suorita-painiketta).
mikä on ihan hyvä, sillä haluamme get()
vain lukulaitteeksi.
mutta nyt instantioidaan Wrapper
kanssa int&
. Yksi käyttötapaus tälle voisi olla kopion välttäminen tai esimerkiksi a
mahdollisten muutosten seuraaminen. Nyt yritetään muokata tallennettua arvoa get()
palauttaman konst-viitteen avulla:
ja jos lyöt juoksun nappiin, näet, että … se komppaa! Ja se tulostaa arvon muunnettuna const-viittauksen kautta, kuin mitään erityistä ei olisi tapahtunut.
Eikö tämä ole hämmentävää? Ettekö tunne sitä rauhoittavaa vaikutelmaa turvallisuudesta, jonka const
luhistuminen ympärillämme antaa? Keneen voimme luottaa?
yritetään ymmärtää, mitä tällä viittauksella tapahtuu.
Const reference vai viittaus const?
asian ydin on se, että A-viittauksemme on const-viittaus, mutta ei viittaus const-viittaukseen.
to undersand what that means, Let ‘ s decompose step by step what is happening in the template instantiation.
get()
menetelmä palauttaa arvon const T&
, kun T
tulee kohdasta template T
. Toisessa tapauksessamme T
on int&
, joten const T&
on const (int&) &
.
katsotaanpa tarkemmin tätä const (int&)
. int&
on viittaus, joka viittaa arvoon int
ja saa muuttaa sitä int
. Mutta const (int&)
on viittaus int&
, joka on const
, eli itse viittausta ei voi muuttaa.
mitä viittauksen muokkaaminen tarkoittaa? Teoriassa se tarkoittaisi sitä, että se viittaisi toiseen kohteeseen tai ei viittaisi mihinkään. Mutta molemmat nämä mahdollisuudet ovat laittomia C++: viittaus ei voi rebind. Se viittaa samaan esineeseen koko sen elämän aikana.
joten ollen const
ei kerro paljoa viitteeksi, koska ne ovat aina const
, koska ne eivät voi rebindata. Tämä viittaa siihen, että const (int&)
on käytännössä samaa tyyppiä kuin int&
.
, jolloin get()
palaa (int&) &
. Ja viittaussääntöjen mukaan tämä on int&
.
joten get
palauttaa int&
. Sen rajapinnassa lukee T const&
, mutta todellisuudessa se on int&
. Ei kovin ilmaisuvoimaista koodia, vai mitä?
miten tehdä const-viittauksesta viittaus const
nyt kun olemme ohittaneet ensimmäisen vaiheen asian ymmärtämisessä, miten voimme korjata sen? Toisin sanoen, miten voimme tehdä get()
palauttamalla tallennettuun arvoon viittauksen, joka ei salli sen muokkaamista?
yksi tapa tehdä tämä on lisätä nimenomainen merkintä const
viitteen sisään. Voimme tehdä tämän poistamalla viittaus, lisäämällä const
, ja laittamalla viittaus takaisin. Poistaaksemme viitteen, käytämme std::remove_reference
C++11: ssä, tai kätevämpää std::remove_reference_t
C: ssä++14:
kuten näet, jos napsautat Suorita-painiketta, odotettu kokoamisvirhe näkyy nyt, kun yrität muokata tiedostoon Wrapper
tallennettua arvoa.
mielestäni on hyödyllistä ymmärtää, mitä tämän viittauksen kanssa tapahtuu, koska tämä on koodi, joka näyttää turvalliselta, mutta ei todellakaan ole, ja tämä on vaarallisin laji.
voit leikkiä yllä olevien leikkipaikkojen koodilla, joka on upotettu sivulle. Ja iso kiitos stack overflow user rakete1111 auttaa minua ymmärtämään syitä tämän ongelman.
saatat pitää myös
- Ärsyttävimmästä Jäsennyksestä: miten sen huomaa ja korjaa nopeasti