C++ const_cast
const_cast
簡介
const_cast
只能作用於指標上,它的作用是為指標去除或加上const
或volatile
關鍵字。
如果我們嘗試將它作用於變數上,則會出現以下錯誤:
error: const_cast to 'int', which is not a reference, pointer-to-object, or
pointer-to-data-member
與C寫法的比較
與簡單的型別轉換相比,它的優點是更為安全,因為它會檢查轉換前後的資料型別是否一致。查看以下例子:
int val = 1000000;
pc = &val;
std::cout << (char *)(pc) << std::endl; //@B
//error: const_cast from 'const int *' to 'char *' is not allowed
std::cout << *const_cast<char *>(pc) << std::endl;
使用C語言中的寫法來做型別轉換可以轉換成功,但是我們會得到一個沒意義的值@B
。
使用const_cast
則會報錯,通知使用者int*
並不能透過const_cast
轉換成char*
。
完整代碼詳見cpp-code-snippets/const_cast.cpp。
修改const變數
對於一個指向const
變數的const
指標,如果使用const_cast
把指標的const
拿掉,再去修改它,那麼結果將會是未定義的。查看以下例子:
int add10(int* ptr)
{
*ptr = *ptr + 10;
return (*ptr);
}
int val = 10;
const int val2 = 10;
int* p;
const int* pc;
pc = &val;
p = const_cast <int *>(pc);
add10(p);
std::cout << std::setw(35) << std::left << "try to add int 10 by 10: " << val << std::endl;
pc = &val2; //指向常數的指標
p = const_cast <int *>(pc);
add10(p);
std::cout << std::setw(35) << std::left << "try to add const int 10 by 10: " << val2 << std::endl;
運行結果為:
try to add int 10 by 10: 20
try to add const int 10 by 10: 10
在第二個實驗中,我們嘗試經由將指向val2
的pc
轉為非const
,然後再透過它去修改val2
的內容,但是結果如上所示,並不會成功。
完整代碼詳見cpp-code-snippets/const_cast.cpp。
TensorRT中的例子
在TensorRT/parsers/caffe/caffeWeightFactory/caffeWeightFactory.cpp
的函數convert
中用到了const_cast
:
void CaffeWeightFactory::convert(Weights& weights, DataType targetType)
{
//...
/**/ convertInternal<float, float16>(const_cast<void**>(&weights.values), weights.count, &mOK);
//...
/**/ convertInternal<float16, float>(const_cast<void**>(&weights.values), weights.count, &mOK);
//...
}
查看convertInternal
函數的簽名:
template <typename INPUT, typename OUTPUT>
void* convertInternal(void** ptr, int64_t count, bool* mOK)
還有TensorRT/include/NvInferRuntime.h
中Weights
類別的定義:
class Weights
{
public:
DataType type; //!< The type of the weights.
const void* values; //!< The weight values, in a contiguous array.
int64_t count; //!< The number of weights in the array.
};
可以發現:&weights.values
是const void**
型別的,在它前面加上const_cast<void**>
是為了要去除const
,讓它變成void**
型別。如此一來,const_cast<void**>(&weights.values)
才能被丟進接受void**
參數的convertInternal
函數裡面。