什么是STL?

发布于 2024-07-18 04:47:01 字数 117 浏览 4 评论 0原文

我不是 C++ 程序员,很难理解网站上给出的解释。 我不懂容器或迭代器,并且近期没有学习 C++ 的计划。 通俗地说:STL 是什么?它能为我做什么? 它与 Python 标准库或 glibc 之类的东西相比如何?

I'm not a C++ programmer and have difficulty understanding the explanations given on websites. I don't understand containers or iterators and don't have plans to learn C++ in the near future. So in layman's terms: What is the STL and what can it do for me? How does it compare to something like the Python Standard library or glibc?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

咋地 2024-07-25 04:47:01

要理解 STL,您至少必须了解 C++ 的某些方面。 我会尽力解释它。 该结构看似简单。 该库的亮点在于使用它可以简化许多复杂的任务。 不过,我将坚持使用一些非常简单的示例,一方面是因为其他任何内容都可能会让不懂 C++ 的人感到困惑,另一方面是因为我不想写小说。 ;)

首先,一些历史。 STL(标准模板库)是单独开发的,然后提交给C++标准委员会考虑,让他们可以选择将其采用到语言中。 但它并不是作为 C++ 标准的一部分开发的,因此,它的设计风格与 C++ 标准库的其余部分非常不同。 如果我记得我的古老历史,标准委员会也花了很长时间才理解 STL 并习惯它。 当他们最初看到它时,并不太喜欢它,但一段时间后,他们意识到它有多么强大和设计精良。 因此它被采用到语言中。 这一切都发生在 20 世纪 90 年代末,当时该语言正接近 ISO 标准化。

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

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

它们通常还提供一些用于遍历这些结构的机制。 (例如,枚举器或迭代器)

STL 在 C++ 中提供了相同的功能,但以一种异常优雅的方式实现,并且具有一些有趣的抽象。

STL 被干净地分为三个独立的组件:

  • 容器(如上所述,每种语言都有这些。数组、ArrayList、字典、集合、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
}

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

std::sort(container.begin(), container.end());

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

我们可以通过提供我们自己的比较器函数(任何接受两个值并在第一个值严格小于另一个值时返回 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);

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

std::sort(container.begin(), container.begin()+5);

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

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

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

STL 的另一个显着特征是使用它时性能损失几乎为零。 C++ 模板在编译时全部被替换,生成的代码可以像您在 C 中手动编码所有内容一样积极优化。上面的排序函数会损失一些性能,因为我将函数指针传递给它作为我的自定义比较器,通常不能内联,但是如果我们这样定义它就可以修复:

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

现在我们不再传递函数指针,而是传递一个对象。 成员函数(例如operator())可以内联。 因此,这个排序函数将与您在 C 中手动编写的任何函数一样高效。

而且,它甚至不需要为排序函数添加任何复杂性。 事实上,sort 恰好有两个重载。 一种采用比较器函数,另一种则不采用。

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

To understand the STL, you're going to have to understand some aspects of C++ at least. I'll try my best to explain it. The structure is deceptively simple. Where the library shines is in how use of it can simplify many complex tasks. I'm going to stick to some very simple examples though, both because anything else will likely confuse someone who doesn't know C++, and because I don't want to write a novel. ;)

First, some history. The STL (Standard Template Library) was developed separately, and then submitted to the C++ standard committee for consideration, giving them the option of adopting it into the language. But it was not developed as part of the C++ standard, and for this reason, it is designed in a style that is very different from the rest of the C++ standard library. If I remember my ancient history, it also took the standard committee a good while to understand the STL and grow used to it. When they initially saw it, they were not too keen on it, but after a while, realized just how powerful and well-designed it was. So it was adopted into the language. This all happened back in the late 1990's, as the language was approaching ISO standardization.

At its core, the STL provides the most fundamental functionality you expect of a standard library: The ability to store sequences of data, and the ability to process these sequences.

Every other language has a Collections/Containers part of its standard library, containing implementations of dynamic arrays (known as arraylists in Java, List in C#, and vectors in C++), linked lists, dictionaries and other common data structures.

They also typically provide some mechanims for traversing these structures. (Enumerators or iterators, for example)

The STL provides the same functionality in C++, but does it in a unusually elegant way, and with some interesting abstractions.

The STL is cleanly split into three separate components:

  • The containers (As described above, every language has these. Arrays, ArrayList, Dictionary, Set, LinkedList and so on. Any data structure that can store a collection of objects is a container in C++)
  • The algorithms (Every language also has these in some form. Algorithms are functions for processing sequences of elements.) For now, assume that a sequence is a container. That's a bit of a simplification, but we'll get to that. Algorithms serve a wide range of purposes, from a for_each() function that allows you to apply a function to every element in a sequence, or the related transform() which applies a function to every element, and stores the result into a separate sequence (very much like the map operation in functional languages), or accumulate (similar to fold in functional languages), but also sorting or searching functions, and functions that allow you to copy entire sequences.
  • And finally, the glue that binds containers and algorithms together: Iterators. As I said above, sequences (which are what the algorithms work on) are not quite the same as containers. The elements in a container certainly constitute a sequence, but the first five elements in a container are also a sequence. Or every other element in a container is a sequence. Data read directly from a file stream can be treated as a sequence as well. Even data that is generated on the fly (say, the fibonacci sequence) can be treated as a sequence of values. Sequences do not have to map to a container, or even to data that exist in memory, although that's the most common use.

Note that these is no overlap between these three areas. A container stores (and owns) data, and produces iterators. Iterators allow you to inspect, modify and traverse the data. And algorithms operate on iterator ranges

Conceptually speaking, an iterator has two functions. It points to some data, and it can be moved around in the sequence (depending on the iterator type, different move operations may be available. Almost all iterators can move to the next element. Some can also move to the previous, and some can jump arbitrary distances backward and forward).
If you're familiar with C, this is going to sound a lot like pointers, and that's no coincidence. Iterators are modeled as a generalization of pointers, and in fact, pointers are also valid iterators. All the STL algorithms work on pointers as well as "real" iterators.

What this means is that any sequence of data can be represented by a pair of iterators: The first iterator points to the first element in the sequence, and the second points one past the end of the sequence.

That allows a fairly simple syntax for traversing sequences in a loop:

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
}

Or we can apply an algorithm to the sequence:

std::sort(container.begin(), container.end());

Note that the sort function does not know or care that it is working on a vector. It is passed two iterators, and these could be of any type. They can be plain pointers into an array, linked list iterators or any other valid iterator type.

We can generalize the sorting function a bit by supplying our own comparer function (any function that takes two values and returns true if the first is strictly less than the other)

// 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);

Of course, we could sort only the first five elements of the vector as well:

std::sort(container.begin(), container.begin()+5);

The begin() and end() functions are just convenience functions to get iterators from a container. We don't have to use them directly.

Another nice trick is that streams too can be generalized into iterators. So let's read all the integers from a file, and copy them to an array (arrays are plain C types, of course, so they're not proper containers and don't have iterators. But pointers work fine)

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

The unique thing about the STL is how flexible and extensible it is. It interoperates cleanly with C code (pointers are legal iterators), it can be simply and easily extended (you can write your own iterator types if you like. Most of the algorithms take custom predicates of comparers, like the one I showed above, and you can define your own containers. That is, each of the three pillars of the STL can be overridden or extended, so STL could be said to be more of a design strategy than anything. You can write STL code even though you're using your own containers, iterators and algorithms. And because each of these three pillars are cleanly separated from the others, they can be swapped out much more easily than in most other languages where these three responsibilities are mixed up and shared by the same classes.
An algorithm does not know which, if any, container the sequence it's operating on are stored in. It only knows that the iterators it has been passed can be dereferenced to get access to the data itself.
A container does not have to support all the standard algorithms. It simply has to be able to produce a pair of iterators, and then all the functionality comes for free.

Compare this to, say, Java, where every collection class has to implement its own search, its own sort, its own everything. In C++, we only need one implementation of find(). It takes two iterators and the value to look for, and it traverses the sequence looking for the value. And so, it works on any container type, even the ones I define myself.

Another remarkable feature of the STL is that there is literally zero performance loss in using it. C++ templates are all substituted at compile-time, yielding code that can be optimized just as aggressively as if you had hand-coded everything in C. The above sort function would lose some performance because I pass a function pointer to it as my custom comparer, which typically can not be inlined, but that can be fixed if we define it as such:

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

Now we no longer pass a function pointer, but an object. And member functions (such as operator()) can be inlined. So this sort function is going to be just as efficient as anything you could hand-code in C.

And again, it doesn't even have to add any complexity to the sort function. In fact, sort has precisely two overloads. One that takes a comparer function, and one that doesn't.

The sort function doesn't need to know whether it is passed a function pointer or an object. As long as the syntax "X(a, b)" is valid, where X is the value it was passed as comparer, and a, b the elements to compare, the same implementation of the sort function will work. And because my greater object overloaded the operator(), that syntax is valid both for this object and for the function pointer we passed earlier.
STL code gets a lot of functionality for free by exploiting tricks like this. The same implementation of a function works with very different argument types because of the way C++ templates work.

小傻瓜 2024-07-25 04:47:01

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

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

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

The STL is the Standard Template Library. It is a subset of the C++ standard library.

The STL provides generic implementations of useful algorithms and containers.

The containers provide any easy method of storing data in the program and then finding, sorting and performing other computations on that data.

梅倚清风 2024-07-25 04:47:01

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

C++ 标准库的部分内容在 1998 年标准化时基于STL; 它后来不断发展(通过 2003 年标准,尤其是现在的 C++0x)。

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

请注意,许多程序员(包括一些多产的书籍作者)出于习惯,仍然使用术语“STL”来指代 C++ 标准库(或最初基于 STL 的部分),尽管这是不正确的。 只要您意识到技术区别,就应该没问题。

希望这会有所帮助。

The Standard Template Library was a library written in C++ before the standardisation of C++. It included cool things like sorting algorithms and containers (and iterators, with which to use these features).

Parts of the C++ Standard Library, when standardised in 1998, were based on parts of the STL; it's since evolved (through the 2003 standard, and especially now with C++0x).

  • The C++ Standard Library is implemented by various compiler vendors (and their friends) and ships with your favourite toolchain.
  • It's this that you're actually likely to use: the STL is all but obsolete by now.

Note that many programmers (including some prolific book authors) still use the term "STL" out of habit to refer to the C++ Standard Library (or to the parts of it that were originally based on the STL), even though this is incorrect. As long as you are aware of the technical distinction, you should be fine.

Hope this helps.

吻安 2024-07-25 04:47:01

如果您不是 C++ 程序员,那么标准模板库的实现对您来说毫无价值。 然而,这些想法超越了任何编程语言。

它是一个数据结构库(例如地图、列表、向量等)。 它包括抽象遍历这些数据结构的迭代器以及对其进行操作的算法。 其他语言也使用这些想法,因此如果您学习一种语言,它们在其他语言中也会很熟悉。

Implementations of the Standard Template Library are worthless to you if you're not a C++ programmer. However, the ideas transcend any programming language.

It's a library of data structures (e.g., maps, lists, vectors, etc.). It includes iterators to abstract traversing those data structures, and algorithms for operating on them. Other languages use these ideas as well, so if you learn them for one language they'll be familiar in others.

左岸枫 2024-07-25 04:47:01

STL 是标准模板库。 它是您可以使用的函数和类库。 它具有基础计算机科学的许多基本算法和数据结构。 如果您打算继续使用 C++,您应该计划学习这个或另一个资源库。

该代码被世界各地的许多人使用,因此您可以放心,该代码经过了良好的测试并且众所周知。

STL is the Standard Template Library. It is a library of functions and classes that you can use. It has many of the basic algorithms and data structures of basic computer science. If you are planning to stay in C++, you should plan on learning this or another library of resources.

The code is used by many many people around the world, so you can be comfortable that the code is well tested and well known.

攒一口袋星星 2024-07-25 04:47:01

它是一个使某些事情变得更容易的库,例如字符串操作、向量、链接列表等。STL 可以让您不必编写一些较低级别的代码,让您更加专注于应用程序代码。

It's a library to make certain things easier, like string manipulation, vectors, linked lists, etc. STL would save you from having to write some of the lower level code and let you focus more on your application code.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文