为什么运算符 [] 不重载左值和右值?
Why isn't operator[] overloaded for lvalues and rvalues?
标准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]);
更新:
在我看来,最重要的一点是,容器本质上是容器,因此它们无论如何都不应该修改其中的元素。它们只是提供存储、迭代机制等。
- 为什么Mat类的两个对象可以在不重载运算符+的情况下添加
- 重载运算符new[]的行为取决于析构函数
- 为什么将值返回函数传递给重载=运算符对运算符函数有效,而对其他运算符无效
- 在 myVector 类中重载运算符 + 时出错
- 为什么常量词在重载运算符中不与 ostream 对象一起使用<<?
- 如何在 cpp 中重载运算符 +=?
- C++ 如何重载 [] 运算符并进行函数调用
- 重载运算符的范围是什么?它是否会影响作为类成员的集合的插入函数?
- 为什么我可以在不重载 "=" 运算符的情况下将一个对象分配给另一个对象?
- 重载运算符有地址吗?
- 如何迭代重载运算符 [] 的类?
- 重载运算符与添加问题
- 模板基类中的重载运算符
- 如何调用用于重载运算符"<<"的 friend 函数?
- 在 C++17 中的命名空间和子命名空间中重载运算符是不明确的
- 重载运算符<<采用谷歌 C++ 风格
- C++ 如何正确重载 + 运算符
- cout (<<) 重载运算符不打印减去的矩阵
- 如何在 c++ 中重载运算符 + 以便能够 whrite c_str = "smth" + c_str;
- 重载运算符*以获取对另一个类的实例的引用