c++ - 成员函数 .begin() 和 std::begin()

标签 c++ c++11 iterator move move-semantics

在右值上调用 std::vectorstd::begin() 的成员函数 .begin() 会导致不同的输出,如下测试所示:

vector<int> a{ 1, 2, 3 };

vector<int>::iterator it1 = move(a).begin(); // OK
vector<int>::const_iterator it2 = move(a).begin(); // OK

vector<int>::iterator it3 = begin(move(a)); // Error!
vector<int>::const_iterator it4 = begin(move(a)); // OK

这是我的理解:std::begin() 调用 const& 重载(因为它缺少 && 重载),因此,它返回一个 const_iterator 对象。因此,返回值可以分配给 const_iterator,但不能分配给 iterator。

  1. 我的理解正确吗?
  2. 为什么 std::begin() 没有右值重载?

请注意,我使用 move(a) 来演示对右值调用 .begin()std::begin() 。当然,它可以被任何定义良好的 .begin()std::begin() 的右值对象替换。

编辑:这是真实的示例,显示了我在哪里遇到此问题。我已经简化了很多,只是为了传达在右值上调用 std::begin() 的想法。因此,由于 row_matrix 是一个代理类,因此在右值上调用 begin 和 end 应该不会有任何问题,因为底层对象是相同的。

class matrix_row;
class row_iterator;

class matrix {
public:
    matrix_row row(int i);
    // other members
};  

class matrix_row { // <- proxy class representing a row of matrix
public:
    row_iterator begin();
    row_iterator end();
    // other members
private:
    int row_;
    matrix& matrix_;
};

class row_iterator {
    // defined everything needed to qualify as a valid iterator 
};

matrix m(3,4);

for(auto x = m.row(1).begin(); x != m.row(1).end(); ++x) {
    *x /=2; // OK
}

for(auto x = begin(m.row(1)); x != end(m.row(1)); ++x) {
    *x /= 2; // Error
}

最佳答案

直到最近,通过调用对象的右值/左值重载 .begin() 仍然是不可能的。

添加后,理论上,将此类更改添加到标准库中可能会破坏现有代码。

破坏现有代码是很糟糕的,糟糕到足以留下遗留的怪癖,除非有相当有力的证据表明此类代码不存在,会有明确的诊断,和/或更改的效果确实有用。

因此 .begin() 忽略其 *this 的右值。

除了可能希望与 .begin() 兼容之外,对 std::begin 没有这样的限制。

理论上,标准容器对于在右值上下文中使用 std::begin 调用没有适当的响应。与 std::move 或右值交互的“正确”方式是,您不应该关心调用完成后移出对象的状态。

这意味着(逻辑上)您只能获取两个迭代器之一(开始或结束)。

在这种情况下,正确的语义是什么是一个很大的困惑。我编写了适配器,在这种情况下(例如,对右值的伪开始/结束调用)生成 move 迭代器,但这样做通常非常令人惊讶,我认为这最终是一个糟糕的举动。

关于c++ - 成员函数 .begin() 和 std::begin(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37262329/

相关文章:

c++ - 返回 vector 最高值的前 5 个索引的函数

c++ - 为什么在调用 GetThreadTimes 时出现错误 "The handle is invalid"?

c++ - std::this_thread::sleep_for() 可以有虚假唤醒吗?

c++ - shared_ptr 的 use_count() 移动到 gcc 4.6.3 中的 std::async

c++11 - 标准前向实现和引用折叠

python - 如何在 python 中找到迭代器的长度而不用尽它?

c++ - 如果列表为空,std list 反向迭代器的尾后迭代器将失效

c++ - 顶点定义框算法中的点?

C++ 流作为函数参数。我可以做类似 function(a << "hi"<< b); 的事情吗?

c++ - 无法在另一个类的迭代器类中使operator <<