【发布时间】:2015-06-01 09:39:34
【问题描述】:
标准 C++ 容器只为 vector<T> 和 deque<T> 等容器提供一个版本的 operator[]。它返回一个T&(除了vector<bool>,我将忽略它),这是一个左值。这意味着在这样的代码中,
vector<BigObject> makeVector(); // factory function
auto copyOfObject = makeVector()[0]; // copy BigObject
copyOfObject 将被复制构造。鉴于makeVector() 返回一个右值vector,期望copyOfObject 被移动构造似乎是合理的。
如果此类容器的operator[] 被右值和左值对象重载,则右值容器的operator[] 可以返回右值引用,即右值:
template<typename T>
container {
public:
T& operator[](int index) &; // for lvalue objects
T&& operator[](int index) &&; // for rvalue objects
...
};
在这种情况下,copyOfObject 将被移动构造。
这种重载一般来说是个坏主意,有什么原因吗? C++14 中的标准容器没有这样做是有原因的吗?
【问题讨论】:
-
我想这可能是不可取的,原因有两个,1) 将
container[0]留空/移动会使重复访问同一元素变得棘手(除非说,container.at(0)没有为右值重载),并且2)auto& ref = container[0]将not work everywhere -
请注意,我们在这里讨论的是右值容器。这意味着重复元素访问很困难,因为容器仅在语句的持续时间内存在。如果您通过将容器绑定到命名引用来延长其生命周期(如您的示例中所示),则该引用是一个左值,并且通过该引用进行的后续访问将调用左值运算符 [] 重载。
-
嗯,一个明显的可能原因是它会破坏现有代码。给定
vector<int> f(); void g(int &);,g(f()[0])将突然停止工作,或者,如果还有void g(const int &);,则默默地转到另一个过载。 -
@T.C.:有效点,谢谢。对于为什么标准容器不会为左值和右值重载 operator[] 的问题,这是一个合理的答案,但是对于遗留代码不是问题的新容器呢?总体设计有问题吗?
-
总体上我认为设计没有问题。毕竟,类成员访问使用非常相似的规则(
E1.E2是一个 xvalue,如果E2命名一个非静态数据成员,E1是一个右值)。std::experimental::optional也使用了类似的设计,但我不记得&&版本是返回T还是T&&。
标签: c++ c++11 operator-overloading