You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++ STL中vector等模板实例化后的代码存放在哪里?

问题描述

我有一段使用C++ vector的极简示例代码如下:

#include <iostream>
#include <vector>
  
using namespace std;
  
int main()
{
    vector<int> g1;
  
    return 0;
}

将上述代码放到在线汇编查看平台编译后,得到如下生成的汇编代码:

main:
        stp     x29, x30, [sp, -64]!
        mov     x29, sp
        str     x19, [sp, 16]
        add     x0, sp, 40
        bl      std::vector<int, std::allocator<int> >::vector() [complete object constructor]
        mov     w19, 0
        add     x0, sp, 40
        bl      std::vector<int, std::allocator<int> >::~vector() [complete object destructor]
        mov     w0, w19
        ldr     x19, [sp, 16]
        ldp     x29, x30, [sp], 64
        ret
__static_initialization_and_destruction_0(int, int):
        stp     x29, x30, [sp, -32]!
        mov     x29, sp
        str     w0, [sp, 28]
        str     w1, [sp, 24]
        ldr     w0, [sp, 28]
        cmp     w0, 1
        bne     .L27
        ldr     w1, [sp, 24]
        mov     w0, 65535
        cmp     w1, w0
        bne     .L27
        adrp    x0, _ZStL8__ioinit
        add     x0, x0, :lo12:_ZStL8__ioinit
        bl      std::ios_base::Init::Init() [complete object constructor]
        adrp    x0, __dso_handle
        add     x2, x0, :lo12:__dso_handle
        adrp    x0, _ZStL8__ioinit
        add     x1, x0, :lo12:_ZStL8__ioinit
        adrp    x0, _ZNSt8ios_base4InitD1Ev
        add     x0, x0, :lo12:_ZNSt8ios_base4InitD1Ev
        bl      __cxa_atexit
.L27:
        nop
        ldp     x29, x30, [sp], 32
        ret
_GLOBAL__sub_I_main:
        stp     x29, x30, [sp, -16]!
        mov     x29, sp
        mov     w1, 65535
        mov     w0, 1
        bl      __static_initialization_and_destruction_0(int, int)
        ldp     x29, x30, [sp], 16
        ret
DW.ref.__gxx_personality_v0:
        .xword  __gxx_personality_v0

我的核心疑问:std::vector<int, std::allocator<int>>::vector() 构造函数的代码可以在哪里找到?

我做了自定义模板类的对照测试,示例代码如下:

#include <iostream>
using namespace std;
  
template <class T, class U> class A {
    T x;
    U y;
  
public:
    A() { cout << "Constructor Called" << endl; }
};
  
int main()
{
    A<char, char> a;
    A<int, double> b;
    return 0;
}

我清楚A<char, char>和A<int, double>实例化后的代码会生成在自身代码对应的目标文件中,但C++ STL的模板类、模板函数,它们实例化生成的目标代码存放在什么位置?
我知道C标准库有对应的库文件比如*libstdc.so*,但编译器并不会把STL模板实例化的代码生成到这个.so文件内部,想搞清楚背后的机制。

解答
  • 你在汇编输出里只看到vector构造函数的调用、看不到对应实现,核心原因是默认编译配置开启了优化:空vector的默认构造、析构逻辑极其简单,构造只需要把内部存储首尾指针、容量指针初始化为空,析构时因为容器没有元素,不需要执行元素销毁、内存释放操作。这类简单的STL模板函数会被编译器标记为弱符号,实例化出的代码最终要么直接被内联、消掉显式函数调用,要么在链接阶段和其他编译单元生成的同名实例合并,全局只保留一份代码。
  • STL模板的实现全部写在头文件中,以GCC配套的libstdc为例,vector默认构造函数的源码就在编译器安装目录下的bits/stl_vector.h文件里。C模板本身不支持分离编译,所有你代码里用到的STL模板实例,都是在编译你自己代码的过程中,直接从这些头文件读取源码完成实例化的,通用模板代码本来就不会提前编译放到libstdc++.so里。
  • libstdc++.so里存储的都是不依赖模板参数、可以提前预编译的固定逻辑:比如IO流的全局状态初始化代码、异常处理的公共运行时逻辑、全局new/delete的实现、RTTI相关的基础函数,还有部分提前做了显式特化的模板实现。
  • 你可以自行验证:编译那段空vector的测试代码时加上-O0参数关闭所有优化,再用objdump -d反汇编生成的可执行文件,就能直接在可执行文件的代码段里找到vector构造、析构的完整汇编——这些代码都是编译你的main文件时,直接从vector头文件实例化生成、写入你自己的目标文件的。
  • 平时你感觉这些代码不在自己的目标文件里,是因为开启优化后,编译器会对STL模板生成的代码做COMDAT段去重、内联、无用代码消除:哪怕项目里10个源文件都实例化了vector<int>的默认构造,最终链接时也只会保留一份代码,不会产生冗余。
  • 还有个编译优化细节需要说明:libstdc会对高频使用的STL模板实例做预编译显式实例化,比如vector<int>的基础成员函数、std::string(即basic_string<char>)的常用方法,这些提前实例化好的代码会存放在libstdc.so里。编译你的代码时,编译器如果检测到对应实例已经有预编译版本,就不会在你的目标文件里重复生成代码,直接链接调用so里的现成实现。这个优化纯粹是为了加快编译速度、减小目标文件体积,不代表模板本身是提前编译到so里的——如果使用不常见的模板参数,比如vector<你自定义的某个类>,对应的实例化代码还是会生成在你自己的目标文件中。

内容的提问来源于stack exchange,提问作者Simon Zhu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.01 12:18:24