2013-12-15 43 views
2

鑑於此代碼(C++,使用Qt容器,但我想這個問題是普遍的):Const正確性導致指針容器問題?

// a containter for Item-s 
QList<Item*> items; 

// argument is const to prevent changing the item by this function 
void doStuff(const Item *item) 
{ 
    // find index of the item inside the container 
    // indexOf() is declared as: 
    // template <typename T> int QList<T>::indexOf(const T &t, int from = 0) const 
    const int itemIndex = items->indexOf(item); 
} 

我得到一個編譯錯誤(MSVC2010):

錯誤C2664:「的QList ::的indexOf:常量項」不能從轉換參數1 '*' 到 '項目* const的&'

[
T =項目*
]
轉換失去限定符

我figurer,由於indexOf()const T &參數聲明的,該參數將成爲一個const Item* &(參照的指針項這是常量),它是從一個const Item*參數可以容易地獲得。不幸的是,自const T& t and T const &t are equivalent以來,出於某種原因,編譯器似乎將參數視爲Item* const &t,它讀作「引用指向項目的const指針」,這是不同的事情,並且不會使Item指向不可變。

我解釋正確嗎?爲什麼編譯器搞砸了,即使函數聲明不會改變參數?這真的是一個const語法等價如何可以搞砸的例子嗎?爲什麼編譯器對前者使用後一種形式?如果我想要將指針存儲在包含器中並保持嚴格的常量語義,我該怎麼辦?

+1

嘗試'items-> indexOf(* item);' –

+0

@MadPhysicist:不起作用,該參數爲'const Item'類型,它不能轉換爲'Item * const&'。 – neuviemeporte

+0

那麼,你的QList是'Item *'列表,而不是'const Item *'。你可以用'QList '逃脫嗎?記住'T *','const T *','T * const'和'const T * const'都是非常不同的東西 – Mike

回答

2

這種情況下,您可以使用const_cast在不違反功能保證的情況下刪除const-度。

// argument is const to prevent changing the item by this function 
void doStuff(const Item *item) 
{ 
    // find index of the item inside the container 
    // indexOf() is declared as: 
    // template <typename T> int QList<T>::indexOf(const T &t, int from = 0) const 
    const int itemIndex = items->indexOf(const_cast<Item*>(item)); 
} 

這是因爲indexOf僅發現在容器中的指針,而不是取消引用指針和變異什麼的另一邊。

+0

有沒有別的辦法?我的意思是,const_cast似乎是如此...矯枉過正?爲什麼編譯器搞砸了這個函數,即使這個函數承諾不會觸及這個參數? – neuviemeporte

+0

@neuviemeporte:幸虧有幾個地方你必須拋棄'const'。但是,存在的少數人是不可避免的。 (另一個地方是'free()'函數,但是當在C中實現'const'正確性時,這個問題更多地出現了。) –

+1

@neuviemeporte:我_think_這是C++ 11應該清理的一種情況完美的轉發。原則上,應該可以安全地將'T *'與'const T *'進行比較,但'indexOf'引用了包含的類型意味着您被卡住了,試圖發送一個對const的引用T *'在'T *'的引用是需要的。儘管我的「右值引用」理解非常非常有限,所以請原諒我的模糊性。任何理想的轉發專家都會關心嗎? –