'reference'typedef的确如何表现?

时间:2011-11-13 06:21:37

标签: c++ stl reference typedef

STL容器有referenceconst_reference typedef,在很多情况下我见过(bool的容器是我能想到的唯一例外) ,可以简单地定义为

typedef value_type& reference;
typedef const value_type& const_reference;

然而,这些类型的语义究竟是什么?

据我所知,他们应该“表现得像对价值类型的引用”,但究竟是什么意思呢?

MSDN说reference是:

  

提供对存储在向量中的元素的引用的类型。

但这究竟是什么意思呢?他们需要超载特定的运营商,还是有特定的行为?如果是,那么所需的行为是什么?

3 个答案:

答案 0 :(得分:4)

我认为问题的一部分来自假设分配器是有用的。分配器(至少预C ++ 11)were something of a late addition to the STL

  

人们想要独立于内存模型的容器,这有点过分,因为该语言不包含内存模型。人们希望图书馆提供一些抽象记忆模型的机制。早期版本的STL假定容器的大小可以表示为size_t类型的整数,并且两个迭代器之间的距离是ptrdiff_t类型。现在我们被告知,你为什么不从中抽象出来呢?这是一个很高的命令,因为语言并没有从中抽象出来; C和C ++数组不是由这些类型参数化的。我们发明了一种名为“allocator”的机制,它封装了有关内存模型的信息。这对图书馆的每个组成部分造成了严重后果。您可能想知道哪些内存模型与算法或容器接口有关。如果您无法使用size_t之类的内容,则由于指针类型不同(T*T*等),您也无法使用T huge *之类的内容。然后你不能使用引用,因为对于不同的内存模型,你有不同的引用类型。图书馆产生了巨大的影响。

不幸的是,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.如果事情变得更好或更糟,分配者会说。


查看对原始问题的评论,因为标准实际上没有说明容器必须如何实现(尽管标准确实对容器的行为提出了如此多的要求,它也可能......),你键入的任何类型,因为reference必须具有某些人在实现容器时可能依赖的行为T&reference类型的对象应该是原始对象的透明别名,分配给它应该改变原始对象的值而不切片,不需要支持“重新安置”reference,取reference的地址应该返回原始对象的地址,等等如果可能的话,它实际上应该是T&;并且唯一可以想象的情况是,如果你正在分配你无法通过指针或引用操作的内存(例如,如果“内存”实际上是在磁盘上,或者内存实际上是分配在一台单独的计算机上,可以通过RPC调用等在网络上访问。)。

答案 1 :(得分:2)

取出标准:

enter image description here

它还将reference定义为value_type&的typedef,它是T的typedef

(之前的新答案是不同的焦点)

答案 2 :(得分:1)

你问的是“我可以一直取消引用一个引用吗?是的,你可以。这意味着取消引用reference可以做所有解除引用value_type&可以做的事情value_type如果这对你有意义的话。


您不能在typedef上重载运算符。 typedef与它们分配的类型具有相同的行为。它们是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
相关问题