lau*_*ent 7 c++ iteration iterator stdmap
显示如何迭代a的示例std::map通常是这样的:
MapType::const_iterator end = data.end();
for (MapType::const_iterator it = data.begin(); it != end; ++it)
Run Code Online (Sandbox Code Playgroud)
即它用来++it代替it++.有什么理由吗?如果我使用它会有任何问题it++吗?
Ker*_* SB 11
经过测试,我制作了三个源文件:
#include <map>
struct Foo { int a; double b; char c; };
typedef std::map<int, Foo> FMap;
### File 1 only ###
void Set(FMap & m, const Foo & f)
{
for (FMap::iterator it = m.begin(), end = m.end(); it != end; ++it)
it->second = f;
}
### File 2 only ###
void Set(FMap & m, const Foo & f)
{
for (FMap::iterator it = m.begin(); it != m.end(); ++it)
it->second = f;
}
### File 3 only ###
void Set(FMap & m, const Foo & f)
{
for (FMap::iterator it = m.begin(); it != m.end(); it++)
it->second = f;
}
### end ###
Run Code Online (Sandbox Code Playgroud)
与编译后g++ -S -O3,GCC 4.6.1,我发现,版本2和3产生相同的组件,和版本1的区别仅在于一个指令,cmpl %eax, %esiVS cmpl %esi, %eax.
所以,请选择并使用适合您风格的任何东西.前缀增量++it可能是最好的,因为它最准确地表达了您的要求,但不要挂断它.
小智 7
使用预增量运算符与后增量运算符相比,性能略有提升.在设置使用迭代器的循环时,您应该选择使用预增量:
for (list<string>::const_iterator it = tokens.begin();
it != tokens.end();
++it) { // Don't use it++
...
}
Run Code Online (Sandbox Code Playgroud)
当您考虑如何实施两种运营商时,原因就会浮出水面.预增量非常简单.但是,为了使后增量起作用,您需要首先制作对象的副本,对原始对象执行实际增量,然后返回副本:
class MyInteger {
private:
int m_nValue;
public:
MyInteger(int i) {
m_nValue = i;
}
// Pre-increment
const MyInteger &operator++() {
++m_nValue;
return *this;
}
// Post-increment
MyInteger operator++(int) {
MyInteger clone = *this; // Copy operation 1
++m_nValue;
return clone; // Copy operation 2
}
}
Run Code Online (Sandbox Code Playgroud)
如您所见,增量后实现涉及两个额外的复制操作.如果所讨论的物体体积庞大,这可能非常昂贵.话虽如此,一些编译器可能足够智能,可以通过优化来完成单个复制操作.关键在于后增量通常涉及比预增量更多的工作,因此习惯于将"++"放在迭代器之前而不是之后.
(1)信用链接网站.
从逻辑的角度来看 - 它是一样的,在这里并不重要.
为什么使用前缀one - 因为它更快 - 它更改迭代器并返回其值,而后缀创建临时对象,递增当前迭代器,然后返回临时对象(相同迭代器的副本,在递增之前).由于没有人在这里观察这个临时对象(返回值),所以它(逻辑上)是相同的.
有一个非常大的机会,编译器将优化它.
另外 - 实际上,对于任何类型,这应该是这样的.但它应该是.任何人都可以重载operator++- 后缀和前缀,它们可以有副作用和不同的行为.
嗯,这是一件可怕的事情,但仍有可能.