char* 賦值 const char* 釋放_Effective C++讀書筆記之條款3:儘可能使用const
點選上方藍字關注我們
C++的const關鍵字會強制編譯器實施保持某個值不變的約束,幫助你在編譯期間就能發現錯誤,靈活使用const能提高程式碼質量還能避免不想被改變的值被修改。下面我將從const作用於變數、形參、引用、函式返回值、迭代器、成員變數和成員函式方面講解對const的理解,以及為什麼要儘可能的使用const。
const修飾常規變數
const關鍵字放在變數型別前面則表示不允許修改該變數的值,const還可以修飾指標,當const放在*後面表示該指標不允許指向其他地址,指標變數儲存的地址值不能被改變。我們用程式碼作為示例。
charName[10];
charId = 0;
char*Ptr1 = Name; //普通指標,可以通過Ptr1修改Name的值
constchar*Ptr = Name; //Ptr不能修改Name的值,但是可以指向新的地址
char*constPtr2 = Name; //Ptr2能修改Name的值,但是不能指向其他地址
constchar*constPtr3 = Name; //Ptr3既不能修改Name的值,也不能指向其他地址
constintValue = 10; //正確,被const修飾的變數只能在初始化時賦值
Value = 20; //錯誤!!!被const修飾的變數值不能被修改!!
Ptr1[0] = 'c'; //正確,可以改變Name的值
Ptr1 = &Id; //正確,可以指向其他char型別變數的地址
Ptr[0] = 'a'; //錯誤!!!Ptr不能修改Name的值
Ptr++; //正確,Ptr指向其他char型別變數的地址
Ptr2[0] = 'a'; //正確,Ptr2能修改Name的值
Ptr2 = &Id; //錯誤!!!Ptr2不能指向其他地址
Ptr2++; //錯誤!!!Ptr2不能指向其他地址
Ptr3[0] = 'b'; //錯誤!!!Ptr3不能修改Name的值
Ptr3 = &Id; //錯誤!!!Ptr3不能指向其他地址
使用const關鍵字修飾的變數,在編譯期間編譯器幫你檢查錯誤!而不加const關鍵字則需要人為仔細使用,還要人為的自我約束,在一個複雜的專案中經過多人維護很難避免這種情況。要儘可能的理解並掌握const基本用法,後續的講解都是基於這個基礎上進行的。
儘可能使用const關鍵字理由之一:儘可能讓編譯器強制實施你的約束,幫助你在編譯期間發現可能會修改不想被修改變數的值的錯誤!const修飾迭代器
由於C++的迭代器是由指標實現的,所以const關鍵字放在迭代器型別前面相當於宣告一個T* const指標,可以修改迭代器所指變數的值,不能指向其他地址。迭代器中有const_iterator型別迭代器,相當於聲明瞭一個const T*型別指標,不能修改迭代器所指變數的值,但是可以指向其他地址。我們用程式碼作為示例。
std::vector<int> Vec;
conststd::vector<int>::iterator Iter = Vec.begin(); //const放在迭代器型別的前面,相當於T* const
*Iter = 10; //正確,T* const能修改指向變數的值
++Iter; //錯誤!!!T* const不能指向其他地址
std::vector<int>::const_iterator ConstIter = Vec.cbegin(); //const_iterator相當於const T*
*ConstIter = 11; //錯誤!!!const T*不能修改指向變數的值
++ConstIter; //正確,const T*可以指向其他地址
conststd::vector<int>::const_iterator CconstIter = Vec.cbegin(); //const修飾const_iterator相當於const T* const
*CconstIter = 12; //錯誤!!!const T* const不能修改指向變數的值
++CconstIter; //錯誤!!!const T* const不能指向其他地址
儘可能使用const關鍵字理由之一:使用const修飾迭代器相當於增加了T* const屬性,如果不想修改迭代器作用變數的值,那麼就加上const關鍵字。
const修飾函式返回值
如果是C++內建型別是不能將“=”放在函式表示式的右邊,也就是不能給函式返回值賦值。但是一個定義不好的自定義資料型別,則可能會出現“=”放在函式表示式右邊的異常情況。我們知道C++可以過載運算子,那麼如果const沒有修飾函式返回值則會發生什麼情況?我們看一下下面的例項程式碼。
classRation{
public:
Ration() = default;
~Ration() = default;
intGetValue()const{
returnValue;
}
intGetDecimal()const{
returnDecimal;
}
voidSeyValue(intValue){
this->Value = Value;
}
voidSetDecimal(intDecimal){
this->Decimal = Decimal;
}
private:
intValue;
intDecimal;
};
Ration operator* (constRation &lhs, constRation &rhs)
{
Ration R;
R.SeyValue(lhs.GetValue() * rhs.GetValue());
R.SetDecimal(lhs.GetDecimal() * rhs.GetDecimal());
returnR;
}
我們過載了*運算子,獲取兩個值的乘積。那麼當使用者不小心時,可能會出現下面的用法。
Ration Value1, Value2;
Ration Value3;
(Value1 * Value2) = Value3;
因為(Value1 * Value2)產生了一個臨時變數,這個時候給臨時變數賦值是可以的,但是這麼看就會很奇怪,為什麼要給臨時變數賦值?而且這也不是你想要的。那麼如何避免這種情況發生呢?要避免給函式返回時產生的臨時變數賦值,除了使用者的自我約束外,最有效的辦法就是用const修飾函式返回值,讓編譯器幫你在編譯期間排除這種錯誤!!以下程式碼為例項。
constRation operator* (constRation &lhs, constRation &rhs)
{
Ration R;
R.SeyValue(lhs.GetValue() * rhs.GetValue());
R.SetDecimal(lhs.GetDecimal() * rhs.GetDecimal());
returnR;
}
Ration Value1, Value2;
Ration Value3;
(Value1 * Value2) = Value3; //錯誤!!!,const修飾變數,不能重新賦值
儘可能使用const的理由之一:如果不想修改函式返回的值,那麼就用const修飾函式返回值!避免出現給函式返回值賦值的奇怪現象。
const修飾成員函式
C++修飾成員函式表明,該成員函式不會修改成員變數的值,如果想在const修飾的成員函式改變某些成員變數的值,但是又不想改變其他成員變數的值,則用mutable修飾成員變數。我們用例項程式碼實際看一下。
classTextBlock{
public:
TextBlock() = default;
~TextBlock() = default;
TextBlock(conststd::string&&InitText);
constchar& operator[](std::size_tPosition) const{
std::cout<< "const operator"<< std::endl;
returnText[Position];
}
char& operator[](std::size_tPosition){
std::cout<< "not const operator"<< std::endl;
returnText[Position];
}
std::size_tLength() const{
if(!TextLen){
TextLen = Text.size(); //改變了被mutable修飾成員變數的值
IsValid = true;//改變了被mutable修飾成員變數的值
}
returnTextLen;
}
voidPrint()const;
private:
std::stringText;
mutablestd::size_tTextLen;
mutableboolIsValid;
};
TextBlock::TextBlock(conststd::string&&InitText)
{
std::cout<< "constructor input right value"<< std::endl;
Text = InitText;
}
voidTextBlock::Print() const
{
std::cout<< Text << std::endl;
}
儘可能使用const理由之一:如果在成員函式中,不想修改成員變數的值,則應該用const修飾成員函式!
儘量減少程式碼重複
非const修飾的成員函式可以通過呼叫const修飾的成員函式減少程式碼重複,但是const修飾的成員函式不能通過呼叫非const修飾的成員函式減少程式碼重複,因為非const修飾的成員函式可能會改變成員變數的值!這和const修飾成員函式的初衷是相違背的!我們用例項程式碼看一下非const修飾的成員函式呼叫const修飾的成員函式。
constchar& operator[](std::size_tPosition) const
{
std::cout<< "const operator"<< std::endl;
returnText[Position];
}
char& operator[](std::size_tPosition)
{
std::cout<< "not const operator"<< std::endl;
returnconst_cast<char&>(static_cast<constTextBlock&>(*this)[Position]);
}
儘可能使用const理由之一:非const修飾的成員函式可以通過呼叫const修飾的成員函式,減少程式碼重複。