Nicolai Josuttis的“The C ++ Standard Library”
第9章:STL迭代器声明:
以下可能无法在某个平台上编译:
std::vector <int> coll;
//sort, starting with second element
//- NONPORTABLE version
if (coll.size() > 1){
std::sort(++coll.begin(),col.end());
}
根据平台的不同,++ col.begin()的编译可能会 失败。但是,如果您使用例如deque而不是vector, 编译总是成功的。 ... ...实用程序函数next()和prev()随C ++ 11一起提供 帐户代码可移植性。
有人可以解释一下这种行为吗?
我使用MINGW gcc 4.6.1,Windows操作系统
获得了正确的输出std::vector<int> coll ;
for (int i=15; i>=1; i--)
coll.push_back(i);
sort(++coll.begin(),coll.end());
答案 0 :(得分:3)
Josuttis很好地解释了这个潜在问题的原因:
这个奇怪问题的原因在于向量,
array
和字符串的迭代器可能被实现为普通指针。对于所有基本数据类型(如指针),不允许修改临时值。但是,对于结构和类,允许这样做。
换句话说,这完全取决于std::vector<int>::iterator
是定义为类还是typedef
int*
。标准允许这两者,这就是为什么它可能会导致某些编译器出现问题而不是其他编译器的问题。
当您致电coll.begin()
时,会创建一个右值std::vector<int>::iterator
。如果std::vector<int>::iterator
是具有已实现前缀operator++
的类,则允许修改rvalue,因此它将进行编译。但是,std::vector<int>::iterator
是指向int的指针的typedef,它是基本类型的rvalue,因此可能无法编译。
答案 1 :(得分:1)
++container.begin()
container
std::deque
container.begin()
时,const
始终被定义的行为在技术上是错误的:标准不保证{{1}}为任何内容返回可修改的左值容器类型。当他说“总是成功”时,他真正的意思是“在我所知道的每一个实施中,它都会成功”,这不是完全相同的事情。
公平地说,在C ++ 11之前,类型的非{{1}}对象不可能将其操作限制为左值,但如果你在不久的将来开始看类,也不要感到惊讶不允许赋值,递增和递减rvalues以与基本类型保持一致。
答案 2 :(得分:0)
如果++
返回l值,则可以对vector::begin()
执行++ operator
- 实质上是一个重载vector::iterator
的对象类型。我不认为该标准坚持认为vector::iterator
应该如何实施。兼容的C ++标准库可以将vector<T>
实现为指针 - 即对于vector<T>::iterator
,T*
可能是vector::iterator
,在这种情况下,++操作将无法编译,因为返回是一个r值,你不能增加一个r值。
您当前使用的C ++库将++
实现为具有重载class iter
{
int * p_;
public:
iter(int * p):p_(p) {}
iter & operator ++()
{
++p_;
return *this;
}
};
class A
{
int * p_;
public:
typedef int * iterator;
typedef iter miterator;
iterator get()
{
return p_;
}
miterator ret()
{
return miterator(p_);
}
};
int main(int argc, char **argv)
{
A a;
++a.get(); // Doesn't compile
A::iterator i = a.get();
++i; // compiles
++a.ret(); //compiles
}
&amp;的对象。因此它有效。但这并不意味着它是便携式的。
试试这个程序
{{1}}