我目前正在开发一个需要尽可能少的外部依赖项的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 ++开发人员会发现奇怪的特殊事物。
答案 0 :(得分:9)
#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效率要求。
如果vector
有contains()
成员,则调用肯定是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)。