std :: map + std :: tr1 :: bind +标准算法值得吗?

时间:2008-12-17 21:50:58

标签: c++ algorithm stl bind

这是我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的键的最佳方法(对于我的项目)是将它们存储在一个侧容器中并迭代它。可维护性问题仍然存在。

7 个答案:

答案 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);

这有以下优点:

  1. 更短

  2. 使用命名函数来获取密钥

  3. (可能)更有效率(因为boost::push_back可以在reserve()上调用v

  4. 并且不需要冗余的v.begin()v.end()对。

  5. 任何其他方式都是纯粹的疯狂。