programowanieInżynier systemowy/C++

Opowiedz o różnicach między słowami kluczowymi 'mutable', 'volatile' i 'const' w C++. Do czego są używane, jakie typowe błędy mogą wystąpić przy ich niewłaściwym zastosowaniu?

Zdaj rozmowy kwalifikacyjne z asystentem AI Hintsage

Odpowiedź

const informuje kompilator, że zmienna jest niezmienna (nie może być zmieniana po inicjalizacji). Używane jest do zadeklarowania zmiennych stałych, a także do metod, które gwarantują, że nie zmieniają stanu obiektu.

mutable pozwala na zmianę wartości pola klasy nawet wewnątrz metod const.

volatile informuje kompilator, że wartość zmiennej może być zmieniana gdzieś poza kontrolą programu (np. przez sprzęt) i kompilator nie powinien optymalizować dostępu do niej.

Przykład kodu

class Logger { public: void log() const { ++count; // Dozwolone — count zadeklarowany jako mutable } private: mutable int count = 0; }; volatile int flag; void wait() { while (flag == 0) { /* kompilator nie optymalizuje pętli, ponieważ flag jest volatile */ } }

Pytanie podchwytliwe

„Co się stanie, jeśli zadeklarujesz członka klasy jednocześnie jako const i mutable?”

Odpowiedź: Nie można tego zrobić, to wykluczające się kwalifikatory; kompilator zgłosi błąd.


Przykłady rzeczywistych błędów z powodu niewiedzy na temat niuansów tematu.


Historia

W oprogramowaniu przemysłowym do pracy ze sprzętem programista zadeklarował dane, aktualizowane przez zewnętrzne przerwania, jako zwykłe int. Optymalizacja kompilatora usunęła powtarzające się odczyty tych zmiennych, przez co program "zawiesił się" w nieskończonej pętli. Problem udało się zdiagnozować dopiero po zamianie na volatile int.


Historia

Jedna z klas logowania miała metodę log() const, w której należało aktualizować licznik wywołań. Na początku robiono to przez wskaźnik const_cast, co spowodowało wiele ostrzeżeń i nieoczywistych błędów. Problem zniknął po prawidłowym zadeklarowaniu licznika jako mutable.


Historia

Niektóre metody klasy były zadeklarowane jako const, ale człony typu wskaźnika zmieniały się (np. w celu realizacji buforowania). To prowadziło do naruszenia logiki „const-correctness” i nawet UB, jeśli obiekt rzeczywiście znajdował się w obszarze tylko do odczytu. N należało używać mutable lub zmienić projekt.