成员函数.begin()和std :: begin()

时间:2016-05-16 20:03:28

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

在rvalues上调用.begin()std::vector的成员函数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.

  1. 我的理解是否正确?
  2. 为什么std::begin()没有右值超载?
  3. 请注意,我使用move(a)来演示对rvalues调用.begin()std::begin()。当然,它可以替换为.begin()std::begin()定义良好的任何右值对象。

    编辑:以下是显示我遇到此问题的真实示例。我已经简化了很多,只是为了传达一个在左值上调用std::begin()的想法。因此,由于row_matrix是一个代理类,因为底层对象是相同的,所以在rvalues上调用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
    }
    

2 个答案:

答案 0 :(得分:3)

直到最近,无法通过调用对象的rvalue / lvalue-ness重载OData

添加时,将这些更改改装到标准库中,理论上可能会破坏现有代码。

破坏现有代码是坏的,足够糟糕,遗留的怪癖留下了相当强有力的证据,证明这些代码不存在,有明确的诊断,和/或改变的效果真的很有用。

因此myOdata.xsodata会忽略其.begin()的右值。

.begin()没有此类限制,除了可能希望与*this兼容。

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

这意味着(逻辑上)你只能得到两个迭代器中的一个(开始或结束)。

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

答案 1 :(得分:-1)

23.2.1 / 12州:

  

除非另有说明(明确或通过定义   函数就其他函数而言),调用一个容器成员   函数或将容器作为参数传递给库函数   不得使迭代器无效或更改对象的值   在那个容器内。

DR 2321也希望明确指出:

  

没有移动构造函数(或移动赋值运算符时   allocator_traits<allocator_type>::propagate_on_container_move_assignment::value   如果容器(array除外)使任何容器无效   引用,指针或迭代器引用的元素   源容器。 [注意: end()迭代器不引用任何   元素,因此可能无效。 - 结束说明]

当然,只有将移动到不同的容器中时,这才有用,但事实并非如此。