简体   繁体   English

为什么不为左值和右值重载 operator[]?

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

The standard C++ containers offer only one version of operator[] for containers like vector<T> and deque<T> .标准 C++ 容器仅为vector<T>deque<T>等容器提供了一个版本的operator[] It returns a T& (other than for vector<bool> , which I'm going to ignore), which is an lvalue.它返回一个T& (除了vector<bool> ,我将忽略它),它是一个左值。 That means that in code like this,这意味着在这样的代码中,

vector<BigObject> makeVector();       // factory function

auto copyOfObject = makeVector()[0];  // copy BigObject

copyOfObject will be copy constructed. copyOfObject将被复制构造。 Given that makeVector() returns an rvalue vector , it seems reasonable to expect copyOfObject to be move constructed.鉴于makeVector()返回一个右值vector ,期望copyOfObject被移动构造似乎是合理的。

If operator[] for such containers was overloaded for rvalue and lvalue objects, then operator[] for rvalue containers could return an rvalue reference, ie, an rvalue:如果这些容器的operator[]被右值和左值对象重载,那么右值容器的operator[]可以返回一个右值引用,即一个右值:

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

In that case, copyOfObject would be move constructed.在这种情况下,将移动构造copyOfObject

Is there a reason this kind of overloading would be a bad idea in general?有没有理由一般来说这种重载会是一个坏主意? Is there a reason why it's not done for the standard containers in C++14?是否有理由不为 C++14 中的标准容器完成?

Converting comment into answer:将评论转换为答案:

There's nothing inherently wrong with this approach;这种方法没有本质上的错误。 class member access follows a similar rule ( E1.E2 is an xvalue if E1 is an rvalue and E2 names a non-static data member and is not a reference, see [expr.ref]/4.2), and elements inside a container are logically similar to non-static data members.类成员访问遵循类似的规则(如果E1是右值且E2命名非静态数据成员且不是引用,则E1.E2是 xvalue,请参阅 [expr.ref]/4.2),并且容器内的元素是逻辑上类似于非静态数据成员。

A significant problem with doing it for std::vector or other standard containers is that it will likely break some legacy code.std::vector或其他标准容器执行此操作的一个重要问题是它可能会破坏一些遗留代码。 Consider:考虑:

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

foo(bar()[0]);

That last line will stop compiling if operator[] on an rvalue vector returned an xvalue.如果右值向量上的operator[]返回 xvalue,最后一行将停止编译。 Alternatively - and arguably worse - if there is a foo(const int &) overload, it will silently start calling that function instead.或者 - 可以说更糟 - 如果有一个foo(const int &)重载,它会悄悄地开始调用该函数。

Also, returning a bunch of elements in a container and only using one element is already rather inefficient.此外,在容器中返回一堆元素并且只使用一个元素已经相当低效了。 It's arguable that code that does this probably doesn't care much about speed anyway, and so the small performance improvement is not worth introducing a potentially breaking change.有争议的是,执行此操作的代码无论如何可能不太关心速度,因此小的性能改进不值得引入潜在的破坏性更改。

I think you will leave the container in an invalid state if you move out one of the elements, I would argue the need to allow that state at all.我认为如果您移出其中一个元素,您将使容器处于无效状态,我认为完全需要允许该状态。 Second, if you ever need that, can't you just call the new object's move constructor like this:其次,如果你需要它,你不能像这样调用新对象的移动构造函数:

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

Update:更新:

Most important point is, again in my opinion, that containers are containers by their nature, so they should not anyhow modify the elements inside them.最重要的一点是,在我看来,容器本质上就是容器,所以无论如何它们都不应该修改其中的元素。 They just provide a storage, iteration mechanism, etc.它们只是提供存储、迭代机制等。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM