什么是STL?

24 c++ stl

我不是C++程序员,很难理解网站上给出的解释.我不了解容器或迭代器,也没有计划在不久的将来学习C++.所以用外行人的话说:什么是STL,它能为我做什么?它与Python标准库或glibc相比如何?

jal*_*alf 59

要理解STL,至少要了解C++的某些方面.我会尽力解释它.结构看似简单.图书馆闪耀的地方在于如何使用它可以简化许多复杂的任务.我会坚持一些非常简单的例子,因为其他任何东西都可能会让那些不懂C++的人感到困惑,也因为我不想写一本小说.;)

首先,一些历史.STL(标准模板库)是单独开发的,然后提交给C++标准委员会考虑,让他们可以选择将其纳入语言.但它并不是作为C++标准的一部分开发的,因此,它的设计风格与C++标准库的其他部分非常不同.如果我记得我的古代历史,它也需要标准委员会了解STL并且习惯它.当他们最初看到它时,他们并不太热衷于它,但过了一会儿,意识到它有多么强大和精心设计.所以它被采用到语言中.这一切都发生在20世纪90年代后期,因为语言接近ISO标准化.

STL的核心是提供您对标准库所期望的最基本功能:存储数据序列的能力以及处理这些序列的能力.

每种其他语言都有其标准库的Collections/Containers部分,包含动态数组(在Java中称为arraylists,在C#中为List,在C++中为向量),链表,字典和其他常见数据结构的实现.

它们通常还提供一些穿越这些结构的机制.(例如,枚举器或迭代器)

STL在C++中提供了相同的功能,但它以异常优雅的方式提供,并带有一些有趣的抽象.

STL完全分为三个独立的组件:

  • 容器(如上所述,每种语言都有这些.Arrays,ArrayList,Dictionary,Set,LinkedList等.任何可以存储对象集合的数据结构都是C++中的容器)
  • 算法(每种语言也都有某种形式.算法是处理元素序列的函数.)现在,假设序列是一个容器.这有点简化,但我们会做到这一点.算法有多种用途,从for_each()允许您将函数应用于序列中的每个元素的函数,或将transform()函数应用于每个元素的相关函数,以及将结果存储到单独的序列中(非常类似于映射)在函数式语言中运行,或累积(类似于函数式语言中的折叠),还有排序或搜索功能,以及允许您复制整个序列的函数.
  • 最后,将容器和算法绑定在一起的粘合剂:迭代器.如上所述,序列(算法的工作原理)与容器不完全相同.容器中的元素当然构成一个序列,但容器中的前五个元素也是一个序列.或者容器中的每个其他元素都是一个序列.直接从文件流中读取的数据也可以视为序列.即使是即时生成的数据(例如,斐波那契序列)也可以被视为一系列值.序列不必映射到容器,甚至映射到内存中的数据,尽管这是最常用的.

请注意,这三个区域之间没有重叠.容器存储(并拥有)数据,并生成迭代器.迭代器允许您检查,修改和遍历数据.并且算法在迭代器范围上运行

从概念上讲,迭代器有两个功能.它指向一些数据,它可以在序列中移动(取决于迭代器类型,可以使用不同的移动操作.几乎所有迭代器都可以移动到下一个元素.有些也可以移动到前一个,有些可以向后和向前跳跃任意距离).如果你熟悉C,这听起来很像指针,这并非巧合.迭代器被建模为指针的泛化,实际上,指针也是有效的迭代器.所有STL算法都适用于指针以及"真实"迭代器.

这意味着是数据的任何序列可以通过一对迭代来表示:第一个迭代器指向在序列中的第一个元素,第二个点一个过去的序列的末尾.

这允许在循环中遍历序列的相当简单的语法:

std::vector<int> container;
for (iter it = container.begin(); it != container.end(); ++it)
{
  // perform some operations on the iterator (it) or the element it points to (*it)
  ++(*it); // increment the value the iterator points to
}
Run Code Online (Sandbox Code Playgroud)

或者我们可以将算法应用于序列:

std::sort(container.begin(), container.end());
Run Code Online (Sandbox Code Playgroud)

请注意,sort函数不知道或不关心它正在处理向量.它传递了两个迭代器,它们可以是任何类型.它们可以是指向数组,链表迭代器或任何其他有效迭代器类型的普通指针.

我们可以通过提供我们自己的比较器函数来概括排序函数(任何带有两个值的函数,如果第一个严格小于另一个,则返回true)

// sort in descending order, by passing in a custom comparer which uses greater than instead of less than
bool greater(int lhs, int rhs) { return lhs > rhs; }
std::sort(container.begin(), container.end(), greater);
Run Code Online (Sandbox Code Playgroud)

当然,我们也可以只对矢量的前五个元素进行排序:

std::sort(container.begin(), container.begin()+5);
Run Code Online (Sandbox Code Playgroud)

begin()和end()函数只是从容器中获取迭代器的便捷函数.我们不必直接使用它们.

另一个很好的技巧是流也可以推广到迭代器中.所以让我们从文件中读取所有整数,并将它们复制到一个数组(当然,数组是普通的C类型,因此它们不是正确的容器,也没有迭代器.但指针工作正常)

int arr[1024];
std::ifstream file("something.txt");
// (note, this assumes <= 1024 integers are read)
std::copy(std::istream_iterator<int>(file) // create an iterator pointing to the current position in the file stream
        , std::istream_iterator<int>() // and our "end" iterator. When we reach the end of the stream, testing the two iterators for equality will yield true, and so the operation will halt
        , arr);
Run Code Online (Sandbox Code Playgroud)

STL的独特之处在于它的灵活性和可扩展性.它可以与C代码完全互操作(指针是合法的迭代器),它可以简单轻松地扩展(如果你愿意,你可以编写自己的迭代器类型.大多数算法都采用比较器的自定义谓词,就像我上面展示的那样,并且您可以定义自己的容器.也就是说,STL的三个支柱中的每一个都可以被覆盖或扩展,因此可以说STL更像是一种设计策略而不是任何东西.即使你使用STL代码也可以编写STL代码你自己的容器,迭代器和算法.并且因为这三个支柱中的每一个都与其他支柱完全分开,所以它们可以比大多数其他语言更容易更换,这三种职责混合在一起并由同一个类共享.算法不知道它所运行的序列存储在哪个容器(如果有的话)中.它只知道它已经传递的迭代器可以被解引用以访问数据本身.容器不必支持所有 标准算法.它必须能够生成一对迭代器,然后所有功能都是免费的.

相比之下,比如Java,每个集合类必须实现自己的搜索,自己的排序,自己的一切.在C++中,我们只需要一个find()实现.它需要两个迭代器和要查找的值,并遍历查找值的序列.因此,它适用于任何容器类型,甚至是我自己定义的容器类型.

STL的另一个显着特点是在使用它时几乎没有性能损失.C++模板在编译时都被替换,产生的代码可以像在C中手动编码所有内容一样进行优化.上面的sort函数会丢失一些性能,因为我将一个函数指针传递给它作为我的自定义比较器,通常不能内联,但如果我们这样定义它可以修复:

struct greater {
    bool operator()(int lhs, int rhs) { return lhs > rhs; }
};
std::sort(container.begin(), container.end(), greater());
Run Code Online (Sandbox Code Playgroud)

现在我们不再传递函数指针,而是一个对象.和成员函数(例如操作者())可以被内联.因此,这种排序功能将与您在C中手动编码的任何功能一样高效.

而且,它甚至不必为sort函数添加任何复杂性.实际上,sort恰好有两个重载.一个采用比较器功能,一个不采用比较器功能.

sort函数不需要知道它是传递函数指针还是对象.只要语法"X(a,b)"有效,其中X是作为比较器传递的值,而a,b是要比较的元素,sort函数的相同实现将起作用.并且因为我的greater对象重载了operator(),所以该语法对于此对象和我们之前传递的函数指针都是有效的.STL代码通过利用这样的技巧免费获得许多功能.由于C++模板的工作方式,函数的相同实现适用于非常不同的参数类型.

  • 这就像我在 SO 上读过的最好的答案之一。完美的解释! (2认同)

Tom*_*nen 9

STL是标准模板库.它是C++标准库的子集.

STL提供有用算法和容器的通用实现.

容器提供了在程序中存储数据的任何简单方法,然后查找,排序和执行对该数据的其他计算.

  • C++,Java和C#都有泛型,但每个都以不同的方式实现它们.我们的想法是List或Map或Set的行为不依赖于它们包含的对象类型.这就是泛型允许你做的事情. (3认同)
  • STL!=模板.泛型与模板相当,尽管它们只提供模板可以执行的一小部分.STL是围绕模板提供的功能构建的库.所以不,STL与泛型无关.它建立在与泛型相关的功能上,但STL是一个库,泛型是一种语言功能. (3认同)

Lig*_*ica 7

标准模板库是C++标准化之前用C++编写的库.它包括很酷的东西,如排序算法和容器(和迭代器,使用这些功能).

在1998年标准化时,C++标准库的部分内容基于STL的部分内容; 它是自进化以来(通过2003标准,特别是现在使用C++ 0x).

  • C++标准库由各种编译器供应商(及其朋友)实现,并附带您最喜欢的工具链.
  • 这就是你实际上可能会使用的:STL现在已经过时了.

请注意,许多程序员(包括一些多产的书籍作者)仍然习惯使用术语 "STL"来引用C++标准库(或最初基于STL的部分),即使这是不正确的.只要你知道技术上的区别,你应该没问题.

希望这可以帮助.