这是我question from yesterday的后续行动。我有斯科特迈耶斯关于我写的只写代码的警告。我喜欢原则上使用标准算法来访问std :: map的键或值的想法,但所需的语法是一个小的巴洛克式恕我直言。假设我想将地图的所有键都转储到矢量中。鉴于以下声明,
typedef std::map<int, int> MyMap;
MyMap m;
std::vector<int> v;
哪些代码更易于维护(即可能更少混淆)?
选项#1:
std::transform(m.begin(),
m.end(),
std::back_inserter(v),
std::tr1::bind(&MyMap::value_type::first, _1));
选项#2:
for (MyMap::iterator i = m.begin(); i != m.end(); ++i)
{
v.push_back(i->first);
}
选项1是更标准的库 - 但我必须在精神上分解它以了解正在发生的事情。选项2似乎更容易阅读,代价是可能的小运行时惩罚。我没有因为CPU时间而受伤所以我倾向于选项2.你们同意吗?我应该考虑第三种选择吗?
P.S。在编写这个问题的过程中,我得出结论,读取std :: map的键的最佳方法(对于我的项目)是将它们存储在一个侧容器中并迭代它。可维护性问题仍然存在。
答案 0 :(得分:11)
清晰度总是很聪明。做你以后可以阅读的内容。
你并不是唯一认为标准代码有点迟钝的人。下一个C ++标准将引入lambda functions,因此您可以使用标准算法编写更易读的代码。
答案 1 :(得分:5)
第一个与第二个一样可读和可维护 - if 你知道bind
做了什么。我一直在使用Boost :: Bind(基本上与std::tr1::bind
完全相同),但我没有遇到任何麻烦。
一旦TR1成为官方标准的一部分,您可以放心地假设任何有能力的C ++程序员都会理解它。在那之前,它可能会带来一些困难,但我总是想到短期内的长期。
答案 2 :(得分:4)
你忘了using namespace std::tr1::placeholders
:P
老实说,对于像这样的简单算法,后一代码可能更容易维护。但我实际上倾向于前者(特别是当C ++ 1x给我们lambdas时!),因为它强调编程的功能风格,我个人更喜欢使用循环的命令式风格。
这真是一个不同的招数;标准算法在复杂或通用时最有用,但这两者都不是。
以下是lambdas的样子:
std::transform(m.begin(), m.end(), std::back_insterter(v),
[](MyMap::value_type pair){ return pair.first; }
);
实际上,还有另一种方法,我更喜欢它,但是它的冗长:
using std::tr1::bind;
using std::tr1::placeholders::_1;
std::for_each(m.begin(), m.end(),
bind(&std::vector<int>::push_back, v,
bind(&MyMap::value_type::first, _1)
)
);
使用lambdas(这可能是所有选项中最新且最明确的):
std::for_each(m.begin(), m.end(),
[&v](MyMap::value_type pair){v.push_back(pair.first);}
);
答案 3 :(得分:3)
我说去2)
为了提高性能,您可以从循环中获取m.end()
并保留向量中的空间。
不能等待C ++ 0x和基于范围的for循环;这将使你的循环更好。
答案 4 :(得分:1)
选择#1选项,参见Scott Meyers,Effective STL Item#43,第181页。
答案 5 :(得分:1)
当我昨天查看你的问题时,不是绑定(我使用了很多)强迫我看了两次以理解代码但是map :: value_type :: first我没有机会经常使用。虽然我同意“Clarity总是聪明一点”,但在清晰度之前需要熟悉并且你不会熟悉你不使用的样式......
我还要说,虽然选项2在理解预期目的方面更清楚,但它会更容易隐藏错误(选项1中的任何错误更有可能在编译时可见)。
答案 6 :(得分:1)
我会选择#3选项:
#include <boost/range/adaptor/map.hpp>
#include <boost/range/algorithm_ext/push_back.hpp>
boost::push_back(v, m | boost::adaptors::map_keys);
这有以下优点:
更短
使用命名函数来获取密钥
(可能)更有效率(因为boost::push_back
可以在reserve()
上调用v
)
并且不需要冗余的v.begin()
,v.end()
对。
任何其他方式都是纯粹的疯狂。