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