迭代器的最佳编码风格
best coding style for iterators
一名飞越者说这让他的眼睛流血:
for (std::vector<Agent*>::const_iterator iter = agents.begin(); iter != agents.end(); ++iter)
{
delete *iter;
}
写得更整洁的方法是什么?我想我可以对迭代器类型进行typedef,但在某些类中,这意味着顶部有一大块typedef。我认为这看起来很糟糕。
我会键入定义std::vector<Agent*>
。
在C++11中,您可以对循环进行基于范围的
map<string, string> address_book;
for ( auto address_entry : address_book )
{
cout << address_entry.first << " < " << address_entry.second << ">" << endl;
}
你已经得到了很多答案,但我认为问题很大。。。比它们所暗示的要深刻。他们中的大多数人主要(或专门)关注你正在使用的语法,我认为这通常是这里问题最少的。他们治疗的是症状,而不是疾病。
对于您发布的有意义的for
循环,您有一组指向用new
分配的对象的指针。此外,您正在删除容器中的所有对象,这意味着您基本上将对象的所有权与该容器相关联。
如上所述,for
循环是一种症状。疾病就是设计。当您修复设计时,您不必担心for
循环的语法,因为您不再需要那个循环了。
这就留下了一个严重的问题:为什么首先要存储指向对象的指针?也许对象的复制成本很高,而且您担心当向量扩展其分配时,复制对象的速度会太慢。很可能在这种情况下,你只是弄错了。众所周知,vector
以指数方式扩展其分配,从而使插入分摊了恒定的复杂性。不太为人所知或不太明显的是,同样的指数增长也意味着现有对象的平均拷贝数渐近接近一个常数。在一个典型的实现中,副本的平均数量将在2到3之间。因此,您很有可能只创建一个对象向量,并且您的效率将保持完全足够。在这种情况下,您的循环最多会变成agents.clear()
(即使不需要也很有可能)。
如果您处于一种相对罕见的情况,复制确实是一个问题,那么您可能希望(例如)将agents
定义为vector<shared_ptr<agent> >
,而不是使用原始指针。在这里,不再需要删除指针对象,因为当对象的引用计数达到0时,shared_ptr
将自动处理此问题。
对于C++11,您可以(通常)通过支持移动语义而不是复制来完成大致相同的事情。假设您可以依靠所有编译器的支持,这可能会进一步提高简单性和效率。
这可能不是一个详尽的可能性列表,其他一些可能会导致略有不同的治疗方法。但问题仍然是一样的:找出真正的错误,并解决它。
然而,我要重复一遍:现在,你看到的是一种症状。你需要治好这种病,这样症状就会消失。
编辑:和往常一样,似乎有人误解(或未能理解)矢量是如何工作的。为了便于论证,我将使用他的64K元素示例。为了使数学运算尽可能简单,我将进一步假设向量是完全满的,并且当需要调整大小时,此实现会将向量的大小精确地加倍。
在这种情况下,32K的元素从未被复制过。另有16K已复制一次。另外8K已经复制了两次。另一个4K被复制了三次,2K四次,1K五次,512六次,256七次,128八次,64九次,32十次,16十一次,8十二次,4十三次,2十四次和1十五次(当然,在现实中,真正的实现可能至少从8或10个元素开始,尽管差别不大)。将该总和除以64K得出元素被复制的平均次数:
所以,我们得到的是:
32K* 0
+16K* 1
+ 8k* 2
+ 4K* 3
+ 2K* 4
+ 1K* 5
+512* 6
+256* 7
+128* 8
+ 64* 9
+ 32* 10
+ 16* 11
+ 8* 12
+ 4* 13
+ 2* 14
+ 1* 15
= 65519
将其除以65536,得到向量中元素被复制的平均次数——0.999741。如果我们只添加一个元素,那么我们将这些元素中的每个元素再复制一次,并且只有一个元素被复制了0次。这给了我们1.99971的平均值。
我怀疑要想从中分别得出上限和下限需要大量的想象力:1和2。
事实上,很少有实现能以这种方式工作。大多数设置了更大的最小尺寸(通常是10或20个元素),大多数使用较小的生长因子。对于许多实际尺寸,较大的最小尺寸会减少实际副本数。较小的增长因子增加了上限——但(重要的)上限仍然是一个常数。
#include <algorithm>
void delete_(Agent* agent) {
delete agent;
}
...
std::for_each(agents.begin(), agents.end(), delete_);
Boost是您可以考虑的吗?在这种典型的"for each"循环中,您可以使用Boost的foreach:
#include <boost/foreach.hpp>
BOOST_FOREACH(Agent* a, agents) {
delete a;
}
http://www.boost.org/doc/libs/1_48_0/doc/html/foreach.html
std::vector<Agent*>::const_iterator iter = agents.begin();
while( iter != agents.end() )
{
delete * iter;
iter++;
}
嗯,我的眼睛流血了,因为这条线超过了80列:)
试试这个:
std::vector<Agent*>::const_iterator iter;
for (iter = agents.begin(); iter != agents.end(); ++iter)
{
delete *iter;
}
使用Boost Foreach,并添加#define使其更加美观。
#include <boost/foreach.hpp>
#define foreach BOOST_FOREACH
...
foreach(Agent* p, agents)
{
delete p;
}
C++2011是您的朋友:
std::for_each(agents.begin(), agents.end(),
[](Agent* agent){ delete agent; });
我怀疑他/她在抱怨为STL范围显式编写for循环。还有其他选择,比如<algorithms>
中的std::for_each
。使用较新的编译器,您还可以使用auto
和lambda表达式来更简洁地编写它。
- Qt VTK交互风格的信号到小部件
- 特征:编码风格对性能的影响
- Mozilla C/C++编码风格
- 有没有像Pycharm那样的c++IDE检查编码风格
- C++ / Qt编码风格 - #define 应该去哪里
- 事实上的标准 C++11 编码风格
- 谷歌C++编码风格,没有例外规则.多线程呢?
- 分配和比较编码风格
- c++编码风格
- Java和C++的编码风格之间有什么具体的区别
- 迭代器的最佳编码风格
- Boost::asio这种奇怪的编码风格是什么
- 统一编码风格的Javascript, PHP, C和c++
- 哪些是具有优秀编码风格的开源c++项目?
- 如何确保CMakeLists.txt和FindXXX.cmake的编码风格一致?
- 只允许c++ 11的编码特性和风格
- 编码风格-C++语法问题
- 在 C/C++ 中使用堆栈进行内存管理时的编码风格
- 完全自定义Qt创建器编码风格
- 在Visual Studio和VIM中执行编码风格