为什么运算符 [] 不重载左值和右值?

Why isn't operator[] overloaded for lvalues and rvalues?

本文关键字:重载 运算符 为什么      更新时间:2023-10-16

标准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[]对于 rvalue 和 lvalue 对象被重载,则 rvalue 容器的operator[]可以返回 rvalue 引用,即 rvalue:

template<typename T>
container {
public:
    T& operator[](int index) &;       // for lvalue objects
    T&& operator[](int index) &&;     // for rvalue objects
...
};

在这种情况下,copyOfObject将被移动构造。

这种

重载通常是一个坏主意有什么原因吗?为什么没有为 C++14 中的标准容器执行此操作?

将注释转换为答案:

这种方法本身并没有什么问题;类成员访问遵循类似的规则(如果E1是右值,则E1.E2是xvalue,E2命名非静态数据成员而不是引用,请参阅 [expr.ref]/4.2(,容器内的元素在逻辑上类似于非静态数据成员。

std::vector或其他标准容器执行此操作的一个重大问题是,它可能会破坏一些遗留代码。考虑:

void foo(int &);
std::vector<int> bar();
foo(bar()[0]);

如果右值向量上的operator[]返回 x值,则最后一行将停止编译。或者 - 可以说更糟 - 如果存在foo(const int &)重载,它将静默地开始调用该函数。

此外,在容器中返回一堆元素并且只使用一个元素已经相当低效了。可以说,这样做的代码可能不太关心速度,因此小的性能改进不值得引入潜在的重大更改。

我认为如果您移出其中一个元素,您将使容器处于无效状态,我认为完全需要允许该状态。其次,如果你需要它,你不能像这样调用新对象的 move 构造函数:

T copyObj = std::move(makeVector()[0]);

更新:

在我看来,最重要的一点是,容器本质上是容器,因此它们无论如何都不应该修改其中的元素。它们只是提供存储、迭代机制等。