Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/157.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 在C++;? 向量a;_C++ - Fatal编程技术网

C++ 在C++;? 向量a;

C++ 在C++;? 向量a;,c++,C++,一, for(vector::iterator it=a.begin();it!=a.end();++it) 二, vector::迭代器end=a.end(); for(vector::iterator it=a.begin();it!=end;++it) 哪个更有效?还是相同?2nd更有效,因为它只需要创建一次结束迭代器 智能编译器可能会将第一个优化为第二个,但不能保证这会发生 这实际上是一个有点复杂的优化,因为编译器需要100%确定对end()的任何后续调用都不会产生额外的效果或返回任

一,

for(vector::iterator it=a.begin();it!=a.end();++it)
二,

vector::迭代器end=a.end();
for(vector::iterator it=a.begin();it!=end;++it)

哪个更有效?还是相同?

2nd更有效,因为它只需要创建一次结束迭代器

智能编译器可能会将第一个优化为第二个,但不能保证这会发生


这实际上是一个有点复杂的优化,因为编译器需要100%确定对end()的任何后续调用都不会产生额外的效果或返回任何不同的结果。基本上,它需要知道至少在整个循环中,end()总是返回这样的内容,即end()==对end()的上一次调用。编译器是否进行这种优化并不能保证。

第二种方式显然更好,因为它只调用了一次a.end()。本质上,如果树中有N节点,那么您可以保存对a.end()的N调用

1/典型教程示例

vector<int>::iterator end = a.end();
for(vector<int>::iterator it = a.begin(); it != end; ++it)
a.end()
似乎只执行一次。但是,由于
end
不是
const
,因此可以在循环内对其进行修改

此外,它在外部范围中引入了
end
标识符,污染了它

因此,在性能上有潜在的提高,但在清晰度上没有太大的提高。而且,它要详细得多


我想提出其他几种方法:

3/最佳手册

vector<int>::iterator end = a.end();
for(vector<int>::iterator it = a.begin(); it != end; ++it)
甚至比
v1
更简洁,一目了然即可识别,没有外部范围泄漏,并保证完全迭代(不可能修改边界)

不幸的是:

  • 变量类型中的逗号有问题(因为它依赖于预处理器)
  • 编译时错误是完全神秘的(因为它依赖于预处理器)
注意:理论上,我们可以在这里使用
std::foreach
算法,但老实说。。。在外部定义谓词需要花费太多的精力,这会破坏代码的局部性

5/C++11语句的范围

BOOST_FOREACH(int& i, a)
所有优点:

  • 极其简洁
  • 作为最佳C++手写循环
  • 的性能
  • 保证完全迭代,没有问题
并且没有任何问题(范围泄漏、预处理器魔术)


就我个人而言,我在任何时候(业余项目)都使用C++11范围,在工作时则使用
BOOST\u FOREACH


我避免像瘟疫一样修改我正在迭代的容器,当我需要过滤/删除元素时,我更喜欢依赖STL算法。。。否则很容易搞乱边界条件和迭代器无效。

我认为第一个for循环更确定。如果在此for循环中插入/擦除元素,则您定义的
end
迭代器将无效。例如:

for (int& i: a)
迭代器mend=int_vec.end(),mbegin=int_vec.begin(); while(mbegin!=修复) {
因为他只做了一个调用,他难道不保存N-1个调用吗?实际上他保存了N个调用。在第二种情况下,end()被调用了N+1次(对于N个节点+故障条件),性能差异是否显著取决于此。通常不是,第一个示例是惯用的。哪一个“更好”因此,这取决于上下文。在大多数情况下,第一个是,因为它是惯用的。在性能是一个问题的特定应用程序中,可能值得普遍采用不同的惯用用法;在这种情况下,我会在
for
@tuxday:Ah yes,tru的
初始化部分同时定义运行迭代器和
end
e、 我忘记了失败的尝试。我不同意编译器可以将第一种方式优化为第二种方式,因为向量可以在体中更改。不过,在循环中更改向量可能是不合法的!@tuxuday简而言之——可能,是。确定:否。(编辑:你是对的,但是如果向量被修改,那么编译器肯定无法优化它)不,即使它的返回是常量,如果不进行更多分析,也不可能实现。如果end()呢有副作用吗?那么,即使返回值是const,也无法对其进行优化。我要说的是,编译器必须分析代码,以确保后续对end()的调用将返回相同的结果。在这种情况下,编译器不是依赖于语言功能,而是依赖于静态分析。对不起,@tuxuday,但我不知道如何解释这一点。基本上,编译器可以使用巫毒魔法,从数学上证明,对于循环的所有迭代,对end()的所有调用will==彼此。考虑到编译器必须检查的所有可能性,这并不是一个简单的任务。但是,是的,这是可能的。@tuxuday:优化函数调用有几个条件。第一个条件是编译器应该知道(或推断)函数没有副作用,第二个条件是它应该知道(或推断)函数每次都返回相同的值。第一个值通常可用于模板,但第二个值并不容易:如果您传递对向量的引用(甚至是常量引用)对于循环体中的另一个函数,编译器如何知道此函数不会以任何方式修改向量?第二种形式可以更好地写成:
for(vector::iterator it=a.begin(),end=a.end();it!=end;++it)
vector<int>::iterator end = a.end();
for(vector<int>::iterator it = a.begin(); it != end; ++it)
for(vector<int>::iterator it = a.begin(), end = a.end(); it != end; ++it)
BOOST_FOREACH(int& i, a)
for (int& i: a)
vector<int>::iterator mend = int_vec.end(), mbegin = int_vec.begin();
while(mbegin != mend)
{
    cout << *mbegin << " ";
    int_vec.erase(mbegin);
    // mbegin is automatically invalidated
    // execution of this program causes bizarre runtime_error !
    // never try this at home !
}
vector<int>::iterator mend = int_vec.end(), mbegin = int_vec.begin();
while(mbegin != mend)
{
    cout << *mbegin << " ";
    int_vec.erase(mbegin);
    mbegin = int_vec.begin(); // ok, mbegin updated.
}