我知道像<map>
,<vector>
和<algorithm>
这样的lib可以由用户实现,即使它们不存在于标准库中。
但是C ++ 11 STL中的某些类或函数只是“编译器 - 魔法”,无法手动实现吗?
修改 通过STL,我的意思是标准模板库,它不需要额外的链接。
答案 0 :(得分:27)
如果您指的是源自Alexander Stepanov的标准模板库的标准库的一部分,那么您可以在没有任何编译器“魔法”的情况下实现所有这些(即,您只需要正常的功能其余的C ++标准所要求的。)
算法对迭代器进行操作。它们需要来自迭代器的操作由它们操作的迭代器类定义(见下文)。该算法简单地执行常规操作,例如分配元素和交换元素。
所有迭代器都提供一些操作,例如递增和解除引用。双向迭代器也提供递减,随机访问迭代器提供加法/减法。使用标准编译器功能实现这些功能并不是特别复杂。
容器类似于算法,因为它们主要通过迭代器对数据进行操作。它们还使用allocator类来分配内存,在该内存中创建对象,等等。虽然编写一个分配器过去相当复杂(而且需求记录很少)但是C ++ 11已经大大简化了任务(并且它从不需要任何非标准的任务)。
如果你把“STL”一般意味着标准库,那么是的,有很多部分需要各种编译魔术。
其中一些是根据较低级别的组件定义的,因此(例如)iostream是根据C的getchar / puthchar 1 定义的,用于从/向外界获取数据。其他部分(例如,类型特征,std :: uncaught_exception)提供了由编译器生成的数据的接口,但是通过其他方式不可用于可移植代码。
1.但请注意,尽管iostream是通过C函数进行读写定义的,但它们并不需要实际使用这些C函数,只是为了做同样的事情。 < / p>
答案 1 :(得分:18)
我假设您的意思是C ++ 11标准库,而不是STL(它是20世纪90年代的算法,迭代器和容器库)。
答案取决于“手动实施”的含义。你的意思是纯C ++吗?即没有汇编代码和没有特定于操作系统的功能,如POSIX内存分配功能,甚至是对内核的低级系统调用?
因为如果你准备编写汇编并直接调用内核,你可以实现几乎所有东西,但它不是很实用。即使编写自己的std::malloc()
或operator new
,如果不在sbrk()
之类的较低级别构建它,也很难。如果没有malloc
之类的内容,则很难编写std::allocator
而难以实现std::vector
!
std::system_clock
也依赖于操作系统提供的功能,您需要一个较低级别的API,如POSIX的clock_gettime()
或访问CPU中的硬件时钟。即使std::time()
中定义的<ctime>
也需要类似的内容。
因此,我们假设依赖于C库来获取malloc
等功能是可以的,但我们希望避免编写汇编和非C ++。
无法在纯C ++中有效地实现std::atomic
。您需要一些编译器魔术或汇编代码来提供必要的同步保证。 std::atomic
的libstdc ++实现依赖于GCC的__atomic built-ins,它们是“编译魔术”。 std::atomic
的libc ++实现使用_Atomic
关键字,该关键字由C11定义并由clang++
支持,但未在标准C ++中定义。在这两种情况下,库实现都依赖于编译器的非标准功能来提供提供所需行为所必需的特定于平台的程序集。
或者,您可以使用互斥锁低效地实现std::atomic
,但这只会将“魔法”同步属性的要求转移到互斥锁类型上。至少,实现需要提供std::atomic_flag
,这在纯C ++中无法完成。没有std::atomic_flag
其他原子类型和std::mutex
无法在纯C ++中实现,因此需要特定于平台的汇编代码,或者需要使用较低级别的库(如Pthreads)来提供必要的原语(它们本身将以汇编或非可移植编译器魔法实现。)
正如How does std::async "store" an arbitrary exception?所指出的,C ++运行时的某些部分,例如std::typeinfo
和std::exception_ptr
,可以用C ++编写,但不能移植。运行时必须定义RTTI和异常处理的数据结构和内部细节,并提供编译器将调用的入口点,以便例如C ++代码中的throw
从运行时调用相关例程来分配异常对象。所以你可以自己实现这些东西,但除非你遵守正确的API,否则编译器不会使用它们,所以它们不起作用!
但即使你准备编写程序集并直接调用内核,几个类型的特性依赖于编译器魔法而无法由用户实现,例如is_standard_layout
,is_trivial
,{ {1}}和其他is_trivially_constructible
特征。这些都依赖于代码中无法测试的类型的属性,只有编译器可以进行必要的检查并告诉您类型是否具有该属性(同样适用于C ++ 14 is_trivially_xxx
特征)。
答案 2 :(得分:11)
并非所有这些都是用户可实现的。有些类只能用编译器扩展来实现。
GCC提供&#34;编译器 - 魔术&#34;对于类型特征。
GCC还提供原子内置,
initializer_list
通常在该编译器本身上实现,可以访问私有函数,在本例中是私有函数。
答案 3 :(得分:-8)
取决于typeid
标头的<typeinfo>
运算符就是一个例子。
另一种情况是initializer_list
,它基本上是一个library附加组件,具有特殊的核心语言权限。例如,它在变量初始化规则中被考虑。
我想还有更多的东西都是附加库和基本语言结构,但那些是我现在能记住的。