2011-11-13 67 views
5

STL容器有referenceconst_referencetypedef,其中,在許多情況下,我已經看到(的bool是唯一的例外容器我能想到的),可以平凡定義爲'reference'typedef究竟如何表現?

typedef value_type& reference; 
typedef const value_type& const_reference; 

究竟,但是,這些類型的語義

從我所瞭解的情況來看,它們應該「像對值類型的引用一樣」,但究竟是什麼意思呢?

MSDN說reference是:

提供對存儲在一個矢量的元素的引用A型。

但這到底意味着什麼?他們是否需要超載特定的操作員,或有特定的行爲?如果是這樣,那麼所需的行爲是什麼?

+2

我不認爲有人會理解這個問題。他在問什麼稱爲「參考」的類型需要表現得像。不是C++引用類型(如'int&')。 –

+0

關於第二個想法,我現在不認爲我理解Q.類型'reference'或'const_reference'的行爲像一個正常的引用或const引用行爲,爲什麼你認爲它應該有任何不同? –

+0

@Als:這個問題的字面意思是:「行爲像一個正常的參考」是什麼意思?這本身就是一個模糊的句子,所以我不知道在我的類型「行爲像一個正常的參考」(如果我正在製作一個容器)之前我需要滿足什麼條件。 – Mehrdad

回答

1

什麼你問的是「我能永遠取消引用引用嗎?是的,可以。這意味着提領reference可以做的一切提領value_type&能做到這一切value_type可以做到。如果這對你有意義。


您不能在類型定義重載操作。類型定義具有相同的行爲,他們被分配到的類型。他們的理由是typedef定義使他們不太麻煩,並提供一個共同的「接口」

reference存在的原因是爲防止這樣的事情:

template<typename T> 
struct foo { 
    T& bar(); 

    typedef T& reference; 
    reference baz(); 
} 

foo<int> x; 
foo<int>::T& y = x.bar(); // error! returns a T& but I can't create one! 
foo<int>::reference z = x.baz(); // ok! 

這也使得簡潔的界面和允許使用SFINAE的:

template<typename T> 
typename T::reference second(T::reference& t) { return t.at(1); }; 

template<typename T> 
T& second(T& t) { return t[1]; }; 

std::vector v(10); 
foo f(10); // type with [] overloaded but no reference typedef 
second(x) = 5; // calls first def 
second(f) = 3; // calls second def 
+1

對不起,但我想你錯過了這個問題。我詢問'reference'類型必須支持哪些運算符/特徵...而不是我是否可以重載那裏的東西......我已經知道'typedef'是如何工作的以及爲什麼他們引入了抽象等等。我只想知道根據標準,「參考」必須滿足什麼要求。 – Mehrdad

+0

@Mehrdad'reference'可以完成所有'value_type&'可以做的事,'value_type'可以做的就是這一切。 – Pubby

+1

那麼,只要使用'value_type&',如果它們是相同的東西,那麼使用'reference'有什麼意義呢? *有*是*參考必須滿足的必要和充分的條件,當然*不是*「所有」...... – Mehrdad

4

我認爲問題的一部分來自於一個假設,即分配器是有用的。 Allocators(至少pre-C++ 11)were something of a late addition to the STL

人們希望獨立於內存模型的容器,因爲語言不包含內存模型,所以容量過大。人們希望圖書館提供抽象記憶模型的一些機制。早期版本的STL假定容器的大小可以表示爲size_t類型的整數,並且兩個迭代器之間的距離類型爲ptrdiff_t。現在我們被告知,你爲什麼不從中抽象出來?這是一項艱鉅的任務,因爲語言不是從中抽象出來的; C和C++數組沒有被這些類型參數化。我們發明了一種叫做「分配器」的機制,它封裝了關於內存模型的信息。這對圖書館中的每個組成部分造成了嚴重的後果。您可能想知道什麼內存模型與算法或容器接口有關。如果您不能使用size_t之類的東西,則由於指針類型不同(T*T huge *等),您也不能使用T*之類的東西。那麼你不能使用引用,因爲不同的內存模型你有不同的引用類型。圖書館有巨大的影響。

不幸的是,they turned out to be substandard

我發明了分配器,以應對英特爾的內存架構。他們在理論上並不是一個壞主意 - 有一個封裝所有內存的層:指針,引用,ptrdiff_tsize_t。不幸的是,他們不能在實踐中工作。例如,

vector<int, alloc1> a(...); 
vector<int, alloc2> b(...); 

你現在不能說:

find(a.begin(), a.end(), b[1]); 

b[1]返回alloc2::reference而不是int&。它可能是一種類型不匹配。有必要改變核心語言處理引用的方式,以使分配器真正有用。

reference的typedef是爲了返回任何的T&相當於是有問題的分配。在現代架構上,這大概是T&。然而,假定在某些體系結構上它可能是不同的(例如,針對具有「近」和「遠」指針的體系結構的編譯器可能需要對「近」和「遠」引用的特殊語法)。可悲的是,這個出色的想法結果並不如人意。 C++ 11對分配器進行了重大更改 - 添加了作用域分配器 - 以及內存模型。我不得不承認我對C++ 11的變化w.r.t不夠了解。分配者說如果事情變得更好或更糟。


望着在原來的問題的評論,因爲該標準實際上並不說明容器必須如何實現(儘管標準沒有把這麼多的要求,對容器的行爲,這可能也是如此。 ..),無論您鍵入的type爲reference必須具有T&的行爲,有人可能在實現容器時依賴這些行爲:reference類型的對象應該是原始對象的透明別名,分配給它應該改變沒有切片的原始對象,沒有必要支持「重置」reference,取reference的地址應該返回o的地址嚴格的對象等等。如果可能的話,它實際上應該是T&;唯一的情況是我可以想象不可能的情況是,如果你分配的內存不能通過指針或引用進行操作(例如,如果「內存」實際上在磁盤上,或者內存是實際的分配在單獨的計算機上,通過RPC調用通過網絡訪問等)。

+0

這似乎是STL,而不是STD。 – Pubby

+1

「我唯一能想象到的情況是不可能的,如果你分配的內存不能通過指針或引用進行操作」標準不會讓你創建任何分配器,因爲你不能僞造在C++中的引用。你不能給一個對象引用sematics。這就是爲什麼'vector '在技術上不是標準容器。它不遵循爲'std :: vector'實例化規定的規則。這並不是因爲你必須能夠完成'&vec [3]',這是'vector '所不可能的。 –

+0

@Pubby:STL在標準之前就已經存在,並且在它成爲標準的一部分時發生了顯着變化(其中一個變化是Stepanov最初的2/3算法已被刪除)。根據Stepanov的說法,當STL被納入標準時,C++在某些方面發生了變化(其中一個變化是函子的增加)。我相信,我在答案的最後一段中的評論只對C++ - 98「正確」。 C++ - 03改變了規則,允許實現假設'reference'實際上是'T'(正如你的回答很明顯)。 –

2

取出的標準:

enter image description here

它還reference定義爲的value_type&一個typedef是T

的一個typedef(新答案爲前一個是不同的焦點)