Powiedzmy, że mam klasę, która wygląda tak (to tylko przykład):
class A {
double *ptr;
public:
A() : ptr( new double[100] ) {}
A( const A &other ) {
other.ptr[7] = 15;
}
void doNotChangeMyData() const {
ptr[43] = 14;
}
void changeMyData() {
ptr[43] = 14;
}
~A() { delete[] ptr; }
};
Zarówno const
w konstruktorze kopiowania, jak i doNotChangeMyData
funkcji sprawiają, że ptr
nie można go zmienić; jednak nadal pozwala mi to modyfikować zawartość tablicy, na którą wskazuje ptr
.
Czy istnieje sposób, aby zapobiec ptr
zmianie zawartości tablicy const
tylko w instancjach, poza „ostrożnością” (lub odejściem od surowego wskaźnika)?
Wiem, że mógłbym zrobić coś takiego
void doNotChangeMyData() const {
const double *const ptr = this->ptr;
ptr[43] = 14; // then this would fail to compile
}
Ale wolałbym nie musieć ...
std::vector
std::vector::operator[]()
czy mogę modyfikować wartości, prawda?vector
zadziałałoby.std::vector::operator[]() const
zwracaconst
referencjęOdpowiedzi:
Wskaźniki nie rozprzestrzeniają się
const
. Dodanieconst
do typudouble*
daje wynikdouble* const
, który powoduje brak wartościconst
po dereferencji.Zamiast tego możesz użyć
std::vector
:a
std::array
:lub wbudowana tablica (niezalecane):
Wszystkie trzy opcje są propagowane
const
.Jeśli naprawdę chcesz używać wskaźników (zdecydowanie nie zalecane), przynajmniej użyj,
std::unique_ptr
aby uniknąć ręcznego zarządzania pamięcią. Możesz użyćstd::experimental::propagate_const
opakowania z podstaw biblioteki 2 TS:Nie ma go jeszcze w standardzie, ale obsługuje go wiele kompilatorów. Oczywiście takie podejście jest gorsze od odpowiednich pojemników.
źródło
std::array
nie działa, jeśli nie znasz rozmiaru w czasie kompilacji.vector
dodaje koszty ogólne;unique_ptr
nie dodaje narzutu, ale jeśli wskaźnik musi być współużytkowany, to potrzebujesz,shared_ptr
który dodaje narzut. Nie sądzę, że VS obecnie obsługujepropagate_const
(przynajmniej plik nagłówka, do którego odwołuje się cppreference, nie istnieje/std:c++latest
) :(vector
jest często zawyżony TBH, szczególnie w porównaniu z wysiłkiem ręcznego zarządzania pamięcią. Ponadto, jeśli współdzielisz wskaźniki ręcznie, musisz użyć liczby referencyjnej, aby narzut nie był specyficznyshared_ptr
. Nie wiedziałem, że VSpropagate_const
jeszcze nie obsługuje (zarówno GCC, jak i Clang obsługują IIRC), ale nie jest trudno wdrożyć własne zgodnie ze specyfikacją.vector
następnie biorę jego zawartość przez.data()
lub&vec[0]
i bezpośrednio z tym pracuję. W przypadku współdzielonego często mam jednego właściciela wskaźnika, który tworzy i usuwa, ale inne klasy współużytkują dane.