2011-03-26 34 views
4

我碰到一些代碼,用這樣的方法來:常數引用到指針

QList<Item*> itemList; 
void addItem(Item* const& item) 
{ 
    itemList.append(item); 
} 

現在,我看不出這之間的任何有意義的區別:

QList<Item*> itemList; 
void addItem(Item* item) 
{ 
    itemList.append(item); 
} 

但很明顯有人走出他們的方式來使用這種奇怪的類型。或者一個重構工具可能出錯了。

是否有任何理由保持該函數簽名?某種角色案件的行爲有所不同?我想不出任何事情。

+5

可能只是'QList :: append'簽名的複製粘貼,它需要'const T&',因爲它是通用的,而且它知道,'T'是複製代價昂貴的。編輯:嘿,不是字面上的複製粘貼,因爲你的代碼有'T const',而我剛剛檢查過的QT文檔有'const T&'。但是精神上一個副本,因爲意思是一樣的。 – 2011-03-26 00:11:22

+0

@Steve這不是通過引用傳遞一個對象,而是將一個指針傳遞給一個對象。將不會有昂貴的複製。 我不能想到任何東西,但可能使用常量迭代器? – 2011-03-26 00:15:36

+0

@Khaled:我知道。我並不是說'Item *'拷貝的代價可能很高。我在說,在'QList'中,'T'可能要複製很昂貴。這個程序員有(我懷疑)複製了一些與'Item *'的具體情況無關的代碼。由於通過'const'引用傳遞指針並沒有什麼錯,他們甚至可能會故意保留它,以便它看起來與'QList :: append'一致 - 當然還有不熟悉'QList'的人,這是不協調的因爲你通常不會以這種方式傳遞指針。 – 2011-03-26 00:17:41

回答

4

唯一的區別是,在第一個版本中,您不允許更改函數內部的本地item的值(您仍然可以修改它指向的Item)。因此,如果您想要Item*由於某種原因保存不同的值,您將被迫使用Item*類型的另一個本地,並且該函數將佔用堆棧空間(boo hoo)的額外字節數(sizeof(intptr_t))。

不是驚天動地,我知道。

+0

謝謝。這似乎是兩者之間差異的一個很好的總結。 – cgmb 2011-03-26 00:25:38

+0

「該函數將消耗額外的sizeof(intptr_t)字節的堆棧空間」 - 如果編譯器足夠垃圾(或者控制流程足夠不可預知),則不會意識到「item」可以在停止使用它的地方被刪除,並開始使用你的額外變量。 – 2011-03-26 00:27:56

+0

爲什麼沒有提到這樣一個事實,即第一項是這個答案中的參考,只是它是一個常量?這不也是一個區別 – Julius 2014-07-22 11:27:27

1

它是對const指針的引用,這意味着你得到這個指針的暱稱,但是你不能改變它指向的地址。

一個指針副本是等價的,如果你使它成爲const。

我聞到了代碼到這一點的歷史變化序列,當然在幾次命名重構之後。

0

它是一個可變引用,指向一個可變值的常量指針。

引用將允許您修改引用的引用,但引用的類型是常量指針,所以指針的值不能更改。指針指向的值可以更改。

void* const &

  • 原始指針:不可變
  • 引用的指針:不可變
  • 原始值:易變

傳遞一個恆定指針直接將是等效的。

void* const

  • 原始指針:不可變
  • 複製的指針:不可變
  • 原始值:易變
+0

有沒有這樣的事情作爲一個可變的參考。引用默認爲const,這就是爲什麼你不能聲明它們爲const(因爲它是多餘的) – 2011-03-26 04:24:07

+0

不正確。一個可變引用是一個引用,通過該引用,該值可以被突變。你指的是'重新引用',這在C++中是不可能的。試圖使參考本身不變是多餘的。 – 2011-03-29 16:56:41

+0

對不起,但你寫了「可變引用常量指針」。這只是沒有任何意義。在你的評論定義後,你必須說「const指向一個指針」。或者你可以正確地說「引用const指針」。但「可變引用常量指針」只是純粹的廢話。 – 2011-03-29 23:44:07

1

第一聲明意味着 「項是一個常數指針參考變量」。您不能將項目更改爲指向ITEM類型的另一個數據,並且它是一個引用,因此它指向作爲被調用函數中參數傳遞的指針。

僞代碼:Item * myItem = new Pen(); additem(myItem); 第一次聲明確保additem函數不會改變筆對象,因爲它是一個常量引用,它也不會複製myItem的內容,它只是指向myItem的內存位置。 第二個聲明具有複製myItem內容的開銷。

0

發生在我身上的另一個重大差異是在堆棧上傳遞的實際數據。在Item*版本中,Item*作爲參數傳遞,需要一個取消引用才能獲得Item值。但是,由於引用是通過傳遞指針在最終機器代碼中實現的,所以Item* const&版本實際上傳遞Item**作爲參數,需要兩個取消引用以得到Item值。

這也解釋了爲什麼你需要額外的棧空間得到修改Item*版本 - 您的來電者實際上並沒有給你在堆棧上Item*(或寄存器),您可以更動的,只有你有一個Item**(或在C++ land中爲Item* const&)。