在 C ++ 中了解迭代器时,我尝试了以下操作:
#include <vector>
int main() {
std::vector<int> a;
a.end()=a.begin();
//Why is this even allowed by the compiler?
}
我错过了什么?
答案 0 :(得分:10)
例如,此代码不会被编译
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;
}