const
qualifiers 在 C 和 C++ 裡面都很常見,
但是觀念不清楚的話就不能好好利用,
以下做些觀念紀錄。
加上 const
關鍵字可以確保不該被改到的變數不被更動,
如果不小心寫錯更動到的話,
會在編譯時噴出錯誤。
- 該加 const 的儘量加
- 愈早加愈好
由右至左解釋變數宣告:
const X p // p is an X that is const
X const p // p is a const X
const X * p // p points to an X that is const
X const * p // p points to a const X
X * const p // p is a const pointer to an X
X const * const p // p is a const pointer to a const X
const X * const p // p is a const pointer to an X that is const
const X& p // p is a reference to an X that is const
X const& p // p is a reference to a const X
void f1(const std::string& s); // Pass by reference-to-const
void f2(const std::string* sptr); // Pass by pointer-to-const
void f3(std::string s); // Pass by value
注意的是在 Pass by Value 的情況下,
參數有沒有加 const
都不會影響函式的 signature,
所以如果有使用 forward declaration 的話,
不需要在宣告時為參數加上 const,
在寫實做時再依需求決定是否加上 const 來向內部標注 read-only 即可。
(反正 Pass by Value 會複製一份,原本的資料到底是不是 const 已經不重要了)
const member function 又稱為 inspectors, 不會更動 object 的 observable state, 也就是對於這個 object 沒有副作用 (內部有標明 mutable 的變數仍然可以更動,例如 Cache, 維護的是 logically const 而不是 physically const):
class MyClass {
public:
void inspect() const; // This member promises NOT to change *this
void mutate(); // This member function might change *this
};
如果想要從 const member function 裡用 reference 的方式回傳 this
object 裡的 member 的話,
必須使用 reference-to-const 或是 by value:
class MyClass {
public:
// inspect member function will return ``this`` object's member
const std::string& inspect_pass_1() const; // Pass, the caller can't change the object
std::string& inspect_fail_1() const; // Compile-time error, the caller can change the object
const std::string inspect_pass_2() const; // Pass, the caller can't change the object
std::string inspect_pass_2() const; // Pass, the caller can't change the object
const std::string& inspect_pass_3(); // Pass
std::string& inspect_pass_4(); // Pass
const std::string inspect_pass_5(); // Pass
std::string inspect_pass_5(); // Pass
};
如果有 member 在 const member function 是會更動的, 但是仍然要把它視為 const member function, 則須把該 member 宣告為 mutable (writable but logically const)。
class MyClass {
public:
void inspect() const { ++count; }
mutable unsigned int count = 0;
};
如果要在多執行緒下跑, mutable 變數要額外做同步, 例如用 mutex 或 atomic 的型別。
const-overloading 指的是有兩個名稱相同的 member function,差別只在 const, 所以 const 和 non-const 的 object 會呼叫到不同函數, 形成 overloading。
class MyClass {
public:
// Subscript operators often come in pairs
const MyClass& operator[] (unsigned index) const;
MyClass& operator[] (unsigned index);
};
同樣是 member function 的 const, C++98 思考的是 single-thread model, 隱含 logically const。 C++11 後思考的是 concurrency model, 隱含的是真的 read-only 或是會同步, 不需要 caller 做額外的同步處理。
- C++ FAQ - Const Correctness
- GotW #6a Solution: Const-Correctness, Part 1
- With C++98, we taught a generation of C++ developers that "const means logically const, not physically/bitwise const".
- With C++11 and onward, const now really does mean "read-only, or safe to read concurrently"-either truly physically/bitwise const, or internally synchronized so that any actual writes are synchronized with any possible concurrent const accesses so the callers can't tell the difference.
- "Concurrent const operations on the same object are required to be safe without the calling code doing external synchronization."
- GotW #6b Solution: Const-Correctness, Part 2
- Does const mean thread-safe in C++11?