为了可读性而包装STL习语是一个好主意吗?

时间:2010-07-29 17:27:16

标签: c++ stl readability

我目前正在开发一个需要尽可能少的外部依赖项的C ++项目,因此我非常关注STL和Boost。到目前为止,在C ++方面,我几乎完全生活在Qt-land。一般来说,我倾向于使用C#和Python。

今天我想检查std::vector是否包含某个项目。有了Qt,我会这样做:

QList< int > list;
list.append( 1 );
list.append( 2 );
list.append( 3 );

if ( list.contains( 2 ) )
{
    // do something
}

美观可读。但是std::vector没有contains方法,这是一个惊喜。好的...这样的STL成语是什么?搜索周围,似乎是这样:

std::vector< int > list;
list.push_back( 1 );
list.push_back( 2 );
list.push_back( 3 );

std::vector< int >::const_iterator result =
    std::find( list.begin(), list.end(), 2 );

if ( result != list.end() )
{
    // do something
}

那(对我而言)难以理解,而且过于冗长。所以我发现自己编写了一个实用函数,它接受一个向量和一个值,并返回bool,具体取决于是否找到了值。基本上,模板contains()方法;上述std::find调用的包装器。然后,我可以以类似于Qt示例的方式使用它。

我有几个类似的实用函数,它们可以包装其他STL习语而没有其他原因,但可读性增加(感知)。我想知道的是......这是一个坏主意吗?其他人也这样做吗?我错过了一些关键的东西吗代码将在某一时刻成为OSS,而我宁愿不做其他C ++开发人员会发现奇怪的特殊事物。

6 个答案:

答案 0 :(得分:9)

增强使它更整洁。我从不使用STL 基于迭代器的算法了。范围 基于算法是一个更整洁的抽象 并使代码更清晰。

#include <boost/range/algorithm/find.hpp>

void foo(){
    std::vector<int> list;
    ...
    ...
    boost::find(list, 2) != list.end()
}

答案 1 :(得分:6)

编写可以帮助您的实用程序功能并使代码更清晰是没有错的。其他人也这样做。 Boost library是最大的此类实用函数和类。

更多说C ++标准明确建议扩展标准库(17.3.1.2/1):

  

可以通过C ++程序扩展库。每个条款(如果适用)描述了此类扩展必须满足的要求。此类扩展通常是以下之一:

     
      
  • 模板参数
  •   
  • 派生类
  •   
  • 符合接口约定的容器,迭代器和/或算法
  •   

答案 2 :(得分:3)

我说这绝对是个好主意。 C ++ STL缺少许多Python / C#程序员对标准库的期望。如果您可以通过采用2-3行STL方法使其代码更具可读性并使其成为单一功能,那么请继续!

以下是另一个非常类似问题的示例:我经常要将int转换为std::string。令我惊讶的是,使用STL没有简洁的方法。因此,我编写了一个toStr函数,该函数运行将int放入stringstream所需的2-3行,并返回结果string

编辑:为了澄清,我建议您在创建自己的解决方案之前先查找boost个解决方案。我的例子旨在证明STL的局限性,但有另一种解释,“无论STL缺失什么,boost都有。”

答案 3 :(得分:1)

类似地,在我当前的项目中,我们有一个名为:stlutils.h的文件,其中包含一些方法,例如contains()。实现为:

template<class Container, class T>
bool contains(const Container& c, const T& value) {
   return std::find(c.begin(), c.end(), value) != c.end();
}

还有更多功能,但我认为你明白了这一点

答案 4 :(得分:1)

其他答案已经指出,您可以编写实用程序功能来为您执行此操作,这是您需要它的好主意。但我想我会指出一个重点:STL是围绕算法效率设计的。几乎所有使用STL的操作都具有标准规定的大O效率要求。

如果vectorcontains()成员,则调用肯定是O(n),因为vector是一个简单的连续列表。由于它也很方便,它可能会鼓励程序员定期使用它,即使是在大型数据集上,也可以鼓励设计具有较差算法性能的应用程序。在contains()的情况下,如果查找容器是否包含某个元素很重要,并且所有元素都是唯一的,那么std::set几乎肯定是一个更好的选择。 log n)效率查找,甚至是std::unordered_set的O(1)。

所以我的个人观点:了解STL提供的所有容器和功能,你会发现它虽然很简洁,但却鼓励更有效的编程风格。你在问题中询问你是否遗漏了什么,我会说是 - 你想更仔细地思考你使用的容器。这些天我经常使用set代替vector

答案 5 :(得分:1)

我不是包装纸的忠实粉丝,但如果他们帮助你,那就去吧。我想你会发现随着时间的推移,除了std :: vector之外你还会想要使用你的实用函数和其他容器。最终你的效用函数变得如此通用,你也可以直接使用std :: find。

但你确定你使用的是合适的容器吗? std :: set有一个方法count(),它基本上等同于contains()。它是O(log(n)),而不是O(n)。