成员函数 .begin() 和 std::begin()
Member function .begin() and std::begin()
调用 std::vector
的成员函数.begin()
和右值上的 std::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.
- 我的理解正确吗?
- 为什么
std::begin()
没有右值重载?
只是一个注释,我用move(a)
来演示调用.begin()
和std::begin()
右值。当然,它可以替换为任何定义.begin()
和std::begin()
的 rvalue 对象。
编辑:这是显示我遇到此问题的真实示例。我简化了很多,只是为了传达在右值上调用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
的价值.
std::begin
没有这样的限制,除了可能希望与.begin()
兼容。
从理论上讲,标准容器对在右值上下文中使用 std::begin
调用没有适当的响应。 与std::move
或右值交互的"正确"方式是,在调用完成后,您不应该关心移自对象的状态。
这意味着(逻辑上(您只能取出两个迭代器中的一个(开始或结束(。
在这种情况下,正确的语义是什么是一个很大的困惑。 我已经编写了适配器,在这种情况下(对右值的伪开始/结束调用(会生成移动迭代器(例如(,但总的来说这样做是非常令人惊讶的,我认为这最终是一个糟糕的举动。
23.2.1/12 指出:
除非另有说明(明确或通过定义 函数,就其他函数而言(,调用容器成员 函数或将容器作为参数传递给库函数 不得使迭代器无效或更改对象的值 在该容器内。
DR 2321 还希望明确说明:
没有移动构造函数(或移动赋值运算符
allocator_traits<allocator_type>::propagate_on_container_move_assignment::value
为 true(的容器(array
除外(使任何 引用引用 源容器。[注意:end()
迭代器不引用任何 元素,因此它可能无效。— 尾注]
当然,这只有在您移动到不同的容器时才有用,但事实并非如此。
- 调用'begin(int [n])'没有匹配函数
- 有没有函数可以在擦除 c++ 中获取 deque.begin() 的 int 值?
- 错误:调用'begin(long double [nPoints])'没有匹配函数;使用硬编码的 int 与整数变量初始化向量
- 使用 std::set 的 .begin() 和 .end() 函数会产生意想不到的结果
- 为什么 free 函数不能在 C 数组上运行,而 std::begin 在某些情况下可以在 C++14 中运行?
- 将模式包装为 std::begin; 返回 begin(c); 到函数中
- C++ 指针上的开始/结束 (arr) - 调用 'begin(int**&)' 没有匹配函数
- 如何使用begin()自由函数
- 成员函数 .begin() 和 std::begin()
- 非成员函数 begin()/cbegin() 及其 constexpr-ness
- 使用 C++11 的 begin() 和 end() 函数通过参数确定数组维度
- 调用 'begin(int**&)' 没有匹配函数
- 避免通用容器中 begin() 和 end() 函数的重复代码
- begin() 和 end() 函数不应该是模板类 Vector 的成员函数吗?
- 迭代一个STL容器,而不是从.begin()函数开始
- Iterator::Begin()函数错误
- 为我的向量包装器和迭代器返回'begin'和'end'函数返回什么?
- C++11 std::begin 不适用于传递给模板函数的 int[]
- 从特定位置调用Upper_bound函数,而不是使用data.begin()
- 依赖begin()函数的Const迭代器