为什么编译器允许C ++中的vector.begin()= vector.end()?

时间:2014-09-21 11:12:04

标签: c++ vector std

C ++ 中了解迭代器时,我尝试了以下操作:

#include <vector>

int main() {
    std::vector<int> a;
    a.end()=a.begin();
    //Why is this even allowed by the compiler?
}

我错过了什么?

5 个答案:

答案 0 :(得分:10)

如果例如函数end将返回指针,那么它将不可用。

例如,此代码不会被编译

int a[] = { 1, 2, 3 };

std::end( a ) = std::begin( a );

GCC发出错误

error: lvalue required as left operand of assignment
  std::end( a ) = std::begin( a );
                ^

但是,当使用类类型的对象时,它们可以调用ovetloaded copy(或move)赋值运算符。

所以问题出现了为什么函数不返回常量迭代器对象。我认为可以应用operator ++。例如

auto it = ++c.begin();

对于直接访问迭代器作为指针,你可以简单地写

auto it = begin( a ) + 1;

答案 1 :(得分:7)

标准没有指定std::vector::iterator是类类型还是原始指针。

如果它是类类型,则此代码在operator=返回的临时对象上调用a.end()。不是一个非常有用的操作,但合法。 (Rvalues可能有调用它们的函数)。

如果您的库使std::vector::iterator成为指针,则此代码将无法编译,因为简单的赋值需要左侧的左值。

Jarod42指出,如果迭代器的赋值运算符被定义为:

std::vector::iterator& std::vector::iterator::operator =(std::vector::iterator) &;
那么这段代码就是非法的;尾随&表示只有在左值上调用该函数时才能选择该函数。

但它没有这样定义,我猜想委员会并不想让一些法律代码违法而没有充分的理由;也许还有一个没人想到的用例。

答案 2 :(得分:3)

该行影响临时迭代器,因此没用。

允许std::vector::iterator = std::vector::iterator

一种不允许的方法是

std::vector::iterator::operator =(std::vector::iterator) &; // note the extra &

但是std::vector::iterator可能是一个简单的指针,我们无法取消T* = T*

答案 3 :(得分:2)

您无法在C ++中分配rvalue(aka temporary)原语类型,如(int)7或函数返回的值。这很有意义,因为赋值的结果会被立即丢弃,所以它可能不是程序员想要的。右值是指=符号右侧的&#39;来自语言语法,或临时(匿名)值。

但是对于类类型的对象,=只调用operator=。通常当lhs是rvalue时,这没有任何意义,但有时它会(比如,类是一个代理对象伪引用(就像[]上的std::vector<bool>返回)。所以它是在特殊情况下对待nit,它只是调用方法。并且没有办法判断该方法是从临时右值还是真正的左值调用的。

rvalue引用是C ++ 11中的新引用,rvalue限定方法也是如此。

在C ++ 11之前,没有办法阻止在类类型的对象上调用operator=,因为它只是暂时的。

begin返回非const临时值时,如果它是类类型(标准不保证),则可以将其赋值。

今天我们可以阻止分配给类类型的临时代码,但是标准库还没有被修改以阻止它的类型。可能至少部分是为了避免向后兼容性问题,部分是为了首先确定std之外的最佳实践。

答案 4 :(得分:1)

它们是允许的,因为迭代器对象是可复制赋值和可复制构造的。这就是为什么我们可以做类似a.begin()= a.end()的事情。此外,我们可以自动执行它(a.begin())。

请查看以下有关复制可分配的示例。

#include <vector>

struct CopyConsAssignable
{
    int x;
    CopyConsAssignable(int a) 
    { 
        x = a; 
    }

    CopyConsAssignable(const CopyConsAssignable& other)
    {
        x = other.x;
    }

    CopyConsAssignable& operator=(const CopyConsAssignable& other)
    {
        if (this != &other)
        {
            x = other.x;
        }
        return *this;
    }
};


int main()
{
    std::vector<int> a;
    a.begin() = a.end();

    CopyConsAssignable(2) = CopyConsAssignable(4); // Allowed as the objects are copy-assignable
    return 0;
}