2011-11-13 61 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(新答案为前一个是不同的焦点)