C++专业程序员如何实现常见的抽象?

9
我从未职业地使用过 C++,只在作为学生时用 (Visual) C++。我在处理缺乏抽象化的情况下遇到了困难,特别是在STL容器类方面。例如,vector类中不包含一个简单的remove方法,这在许多库(如.NET Framework)中很常见。我知道有一个erase方法,但它并不能将remove方法抽象化到足够程度,以使操作简化为单行方法调用。例如,如果我有一个

std::vector<std::string>

我不知道还有什么其他方法可以从向量中删除字符串元素,而不是通过迭代并搜索匹配的字符串元素。

bool remove(vector<string> & msgs, string toRemove) {
if (msgs.size() > 0) {
    vector<string>::iterator it = msgs.end() - 1;   
    while (it >= msgs.begin()) {
        string remove = it->data();
        if (remove == toRemove) {
            //std::cout << "removing '" << it->data() << "'\n";
            msgs.erase(it);
            return true;
        }
        it--;
    }
}   
return false;

}

在这种情况下,专业的C++程序员会做什么?您每次都编写实现吗?您是否创建自己的容器类、帮助函数库,或者建议使用其他库,例如Boost(即使您在Visual Studio中编写Windows程序)?还是其他什么?
(如果上述“删除”操作需要改进,请留下另一种方法,谢谢。)

我个人会使用更方便的容器库,我喜欢Qt。当然,一个带有方便的按值删除方法(例如QList<T>::removeAll())的简单列表容器会隐藏复杂的属性。Qt容器还具有其他有益的属性,如隐式共享,其中按值返回实际上是相对廉价的操作。 - Tilman Vogel
如果没有人注意到,上面的代码中有一个错误,这证明了Kerrek SB所说的观点。这是减量操作。 - T. Webster
3个回答

9
您可以使用“删除和清除习语”:
v.erase(std::remove(v.begin(), v.end(), mystring), v.end());

重点是vector是一个序列容器,而不是以为导向的操作。根据您的设计需求,可能需要使用不同的标准库容器。
请注意,remove算法仅重新排序范围内的元素,它并不从容器中删除任何内容。这是因为迭代器不携带有关其容器的信息,这是完全有意的:通过将迭代器与其容器分离,可以编写适用于任何合理容器的通用算法。
惯用的现代C++会尽可能地遵循这种模式:通过迭代器公开数据,并使用通用算法来操作它。

1
@T. Webster:对于所有纯抽象的计算机数据处理,标准库(请不要说“STL”)包含了大量现成的算法,这些算法可能比您自己编写的更有效和正确。当然,您需要其他库来处理终端、图形、网络、图像、字体等框架相关的东西。但是请看看 Boost,这是一个遵循 C++ 标准库设计哲学的庞大库。 - Kerrek SB
1
@T. Webster:与C++98相比,Boost不应该复制标准库中的任何内容,只是扩展它。但现在许多新的C++0x库最初都是在Boost中实现的,因此现在存在一些重叠(例如随机数、正则表达式、函数式、无序容器、元组、内存、线程、原子等)。如果可以,请使用标准库。我只是举了Boost作为标准哲学的例子——即使像图形这样复杂的东西也是通过清晰的接口和实现分离来设计的。 - Kerrek SB
2
@T. Webster:在Visual Studio上使用Boost并不难。事实上,我认为它要容易得多,因为Boost支持Visual Studio的自动链接功能。而且boostpro还提供了方便的安装程序,可以预编译boost 这里 - Benjamin Lindley
2
@Tilman:请注意,操作向您显示的成本是基于“remove”+“erase”的术语,并不意味着它更加昂贵。由于连续内存是一个不变量,从中间删除元素的成本始终会与容器的大小成线性关系。 STL(我使用STL,因为我正在引用原始Stepanov库)专注于泛型和性能,每当有一种可以在特定容器中更有效地实现的操作时,该操作就会添加到容器本身中。 - David Rodríguez - dribeas
2
在这种特定情况下,与您在评论中指出的相反,remove+erase习惯用语在向量和列表中的成本相同,但在列表的情况下,可以更有效地实现相同的操作,因此,std::list作为成员实现了自己特定的remove函数。性能问题是用户需要解决的问题,而不是库。如果您需要使用向量,则remove-erase的速度就是最快的,如果您需要更快的速度,请不要使用向量。 - David Rodríguez - dribeas
显示剩余9条评论

4

0
在我看来,从专业角度考虑,如果标准库没有提供相应的功能实现,编写自定义实现以执行特定任务是非常合理的。这比一遍又一遍地复制和粘贴相同的代码要好得多。可以利用内联函数、模板函数和宏将相同的内容放在一个地方。这样可以减少在重复使用相同内容时可能遇到的任何错误(在“粘贴”时可能出现问题)。它还可以使纠正错误更加容易。
如果正确设计,模板和宏非常有用,并不会使代码变得臃肿。
编辑:您的代码需要改进:
  • bool remove(vector & msgs, cosnt string& toRemove);
  • 使用for循环即可遍历集合,无需检查大小、获取最后一个迭代器并与begin进行比较,再获取数据等操作。
  • 没必要浪费一个string - 直接进行比较并删除即可。
对于您的问题,我认为使用map或set会更适合。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接