Ukazatelé const a volatile
Klíčová slova const a volatile mění způsob práce s ukazateli.Klíčové slovo const určuje, že ukazatel po inicializaci nelze upravit. Ukazatel je po inicializaci chráněn před úpravami.
Klíčové slovo volatile určuje, že hodnotu přiřazenou k následujícímu názvu lze upravit akcemi i mimo aplikaci uživatele.Klíčové slovo volatile je proto užitečné k deklaraci objektů ve sdílené paměti, ke kterým může přistoupit několik procesů nebo oblastí globálních dat používaných pro komunikaci s rutinami služby přerušení.
Je-li název deklarován jako volatile, kompilátor jeho hodnotu znovu načte z paměti pokaždé, kdy k němu program přistoupí.Tím jsou výrazně omezeny možné optimalizace.Pokud však může dojít k nečekané změně stavu objektu, jde o jediný způsob, jak lze zajistit předvídatelný výkon programu.
Chcete-li deklarovat objekt, na nějž ukazuje ukazatel, jako const nebo volatile, použijte deklaraci v následujícím tvaru:
const char *cpch;
volatile char *vpch;
Chcete-li deklarovat hodnotu ukazatele — tedy skutečnou adresu uloženou v ukazateli — jako const nebo volatile, použijte deklaraci následujícího tvaru:
char * const pchc;
char * volatile pchv;
Jazyk C++ znemožňuje přiřazení, která by umožnila úpravu objektu nebo ukazatele deklarovaného jako const.Taková přiřazení by odstranila informaci, s níž byl objekt nebo ukazatel deklarován, a porušila by tak záměr původní deklarace.Považte následující deklarace:
const char cch = 'A';
char ch = 'B';
Jsou-li dány předchozí deklarace dvou objektů (cch typu const char a ch typu char), jsou následující deklarace či inicializace platné:
const char *pch1 = &cch;
const char *const pch4 = &cch;
const char *pch5 = &ch;
char *pch6 = &ch;
char *const pch7 = &ch;
const char *const pch8 = &ch;
Následující deklarace či inicializace jsou chybné.
char *pch2 = &cch; // Error
char *const pch3 = &cch; // Error
Deklarace proměnné pch2 deklaruje ukazatel, pomocí nějž lze upravit konstantní objekt, a proto není povolena.Deklarace proměnné pch3 určuje, že je konstantní ukazatel (pointer), nikoli objekt. Deklarace není povolena ze stejného důvodu, z jakého není povolena deklarace proměnné pch2.
Následujících osm přiřazení ukazují přiřazování pomocí ukazatele a změnu hodnoty ukazatele z předchozích deklarací. Pro tuto chvíli předpokládejme, že pro proměnné pch1 až pch8 byla inicializace správná.
*pch1 = 'A'; // Error: object declared const
pch1 = &ch; // OK: pointer not declared const
*pch2 = 'A'; // OK: normal pointer
pch2 = &ch; // OK: normal pointer
*pch3 = 'A'; // OK: object not declared const
pch3 = &ch; // Error: pointer declared const
*pch4 = 'A'; // Error: object declared const
pch4 = &ch; // Error: pointer declared const
Ukazatele deklarované jako volatile nebo jako kombinace modifikátorů const a volatile dodržují stejná pravidla.
Ukazatele na objekty const se často používají v deklaracích funkcí následujícím způsobem:
errno_t strcpy_s( char *strDestination, size_t numberOfElements, const char *strSource );
Předchozí příkaz deklaruje funkci strcpy_s, kde dva ze tří argumentů jsou typu ukazatele na typ char.Jelikož jsou argumenty předávány referencí, nikoli hodnotou, funkce by mohla libovolně měnit parametry strDestination a strSource, pokud by parametr strSource nebyl deklarován jako const.Deklarace parametru strSource jako const volajícímu zajišťuje, že parametr strSource nelze volanou funkcí změnit.
[!POZNÁMKA]
Vzhledem k tomu, že dochází ke standardnímu převodu z typu název_typu * na typ const název_typu *, lze funkci strcpy_s předat argument typu char *.Naopak to však neplatí. Neexistuje žádný implicitní převod, který by z objektu nebo ukazatele odstranil atribut const.
Ukazatel s atributem const daného typu lze přiřadit ukazateli stejného typu.Ukazatel, který atribut const nemá, však nelze přiřadit do ukazatele s atributem const.Následující kód ukazuje správná i nesprávná přiřazení:
// const_pointer.cpp
int *const cpObject = 0;
int *pObject;
int main() {
pObject = cpObject;
cpObject = pObject; // C3892
}
Následující příklad ukazuje, jak deklarovat objekt jako const, pracujete-li s ukazatelem na ukazatel na objekt.
// const_pointer2.cpp
struct X {
X(int i) : m_i(i) { }
int m_i;
};
int main() {
// correct
const X cx(10);
const X * pcx = &cx;
const X ** ppcx = &pcx;
// also correct
X const cx2(20);
X const * pcx2 = &cx2;
X const ** ppcx2 = &pcx2;
}