int i, *ip = nullptr; // i jest typu int, ip jest wskaźnikiem na int. int* p1, p2; // p1 jest wskaźnikiem na int, p2 jest typu int. int* a, &b = *ip; // a jest wskaźnikiem na int, b jest referencją na wartość // wskazywaną przez ip.A teraz trochę o const. Zawsze jest to dla mnie mylące, przynajmniej po dłuższym okresie czasu, gdy wiedza powolutku wyparowuje.
const int c = 8; // c jest stałą typu int, jego wartość nie może być zmieniona. const int &r = c; // ok, referencja na stały obiekt typu int - mówimy co będziemy mogli // robić przy pomocy referencji - odwołując się do r nie damy rady // zmodyfikować c (chociaż sam w sobie nie jest const). int &r2 = c; // error, referencja na niestały obiekt.Nie ma czegoś takiego jak stałe referencje (z technicznego punktu widzenia), są tylko referencje na stałe. Ponieważ nie można zmusić referencji by wskazywała na inny obiekt w jakimś sensie wszystkie referencje są stałe.
double dval = 3.14; const double *pt = &dval; // ok (tak jak wyżej), ale nie możemy zmieniać dval, przy pomocy ptA teraz co powstanie, gdy const znajdzie się w różnych miejscach? Pewne oznaczenia - cytując za książką:
Używamy terminu top-level const do oznaczenia, że sam wskaźnik jest stały. Kiedy wskaźnik może wskazywać na stały obiekt, odnosimy się do tego jako low-level const
int i = 0; const int c1 = 88; // c1 jest stałym obiektem typu int int const c2 = 99; // (TO SAMO) c2 jest stałym obiektem typu int int *const p1 = &i; // p1 jest stałym wskaźnikiem na obiekt typu int (top-level const). const int ci = 42; // ci jest stałym obiektem typu int (top-level const). const int *p2 = &ci; // p2 jest wskaźnikiem na stały obiekt typu int (low-level). int const *p3 = &ci; // (TO SAMO) p3 jest wskaźnikiem na stały obiekt typu int. const int *const p4 = p2; // p3 jest stałym wskaźnikiem na stały obiekt typu int // (prawy const jest top-level; lewy nie) const int &r = i; // referencja na stały obiekt typu int. // const w typach referencyjnych zawsze jest low-level.W odróżnieniu od referencji, wskaźniki są obiektami, więc mogą być const, co znaczy, że po ustawieniu w momencie inicjalizacji nie mogą na nic innego wskazywać.
A teraz o nowościach. const expression jest wyrażeniem, którego wartość nie może zostać zmieniona, i dla którego wartość powinna być (ale nie musi) obliczona podczas kompilacji. W C++11 pojawia się nowy modyfikator constexpr, który zbada, czy tak rzeczywiście się stanie. Funkcje z constexpr muszą być na tyle proste by kompilator poradził sobie z nimi podczas kompilacji, ale w kolejnych wersjach standardu konstrukcje będą stawać się coraz bardziej skomplikowane (pętle, algorytmy STL, kontenery itp.). W zamyśle constexpr ma stać się alternatywą dla metaprogramowania w szablonach.
#include <iostream> #include <stdio.h> using namespace std; constexpr int get_size() { return 6; } int main() { constexpr int sz = get_size() + 80; // ok, pod warunkiem, że funkcja też jest constexpr. printf("%d", sz); return 0; }I podgląd tego co wyprodukował kompilator (g++ -std=c++17 -S -masm=intel main.cpp). Jak widać w pliku binarnym pojawia się już obliczona wartość (80+6=86).
main: .LFB1824: .cfi_startproc endbr64 push rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 mov rbp, rsp .cfi_def_cfa_register 6 sub rsp, 16 mov DWORD PTR -4[rbp], 86 mov esi, 86 lea rdi, .LC0[rip] mov eax, 0 call printf@PLT mov eax, 0 leave .cfi_def_cfa 7, 8 ret .cfi_endproc
Brak komentarzy:
Prześlij komentarz