gpt4 book ai didi

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

转载 作者:搜寻专家 更新时间:2023-10-31 02:16:11 32 4
gpt4 key购买 nike

在右值上调用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 是一个代理类,因此在右值上调用 beginend 应该没有任何问题,因为底层对象是相同的。

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 的右值性。

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

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

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

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

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

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com