在C++标准模板库(STL)中,vector作为动态数组容器,其构造函数的设计直接影响内存管理效率、对象初始化方式及异常安全性。vector构造函数通过多种重载形式,覆盖了默认构造、范围初始化、填充值构造、拷贝/移动语义等场景,同时支持自定义内存分配器与强制指针转换。这些构造函数不仅需平衡性能与灵活性,还需处理复杂的内存分配逻辑,例如在范围构造时通过迭代器动态计算容量,或在填充构造时优化内存预分配。不同构造函数的底层实现差异显著,例如默认构造仅初始化空容器,而填充构造需调用分配器的max_size函数进行空间校验。此外,异常安全性是核心考量,如强异常安全保证(basic_guaranteed)在构造失败时自动释放资源。本文将从八个维度深度剖析vector构造函数的特性,并通过对比表格揭示其性能与内存行为的差异。

v	ector 构造函数

1. 默认构造函数

默认构造函数创建空容器,不分配存储空间。其底层实现仅初始化成员变量(如start、finish、end_of_storage),并将size/capacity设为0。该构造函数无参数,适用于需要延迟初始化的场景,例如全局变量或临时对象。

2. 填充值构造函数

接受整数n与值类型参数,创建包含n个相同值的容器。底层实现分为两步:先调用分配器的allocate(n)分配内存,再通过uninitialized_fill_n批量赋值。若n为0,则直接返回空vector。异常安全性由分配器的allocate函数保障,若分配失败抛出bad_alloc异常。

3. 范围构造函数

通过[First, Last)迭代器范围初始化容器。底层需两次遍历:首次遍历计算元素数量并预留容量,再次遍历执行拷贝构造。对于输入迭代器,需采用逐步扩容策略;对于随机访问迭代器,可直接计算距离并预分配空间。时间复杂度为O(N),其中N为范围元素数量。

4. 拷贝构造函数

执行深拷贝操作,包括元素复制与分配器拷贝。新vector的allocator独立于原对象,但若分配器相等,则可复用原有内存块。拷贝过程通过copy算法完成,异常安全性由强异常保证机制处理,确保部分拷贝失败时不泄露资源。

5. 移动构造函数

转移源vector的存储空间而非复制元素。新vector的start/finish/end_of_storage指向源对象对应指针,并将源对象的指针置为空。此操作不会触发元素析构,仅转移所有权,时间复杂度为O(1)。但需注意移动后源对象处于有效但未定义状态。

6. Allocator构造函数

允许指定自定义内存分配器,影响内存分配策略。标准分配器使用::operator new,而用户可传入池分配器或对齐分配器。构造函数需验证分配器类型是否匹配,例如在C++11中要求Alloc::rebind匹配value_type。

7. 强制指针构造函数

接受指针与数量参数,将普通数组转换为vector。底层调用destroy(p)销毁原始数组,再通过uninitialized_copy复制数据到新分配空间。此构造函数不保证异常安全,若目标空间不足可能抛出异常导致内存泄漏。

8. 自定义异常规范构造函数

C++11新增异常规范重载,允许显式指定nothrow版本。底层调用分配器的allocate(n, tag),其中tag决定是否抛出异常。若分配失败且未指定nothrow,则抛出bad_alloc;若指定nothrow则返回空vector。

构造函数类型参数特征时间复杂度内存分配次数
默认构造无参数O(1)0次
填充值构造size_type n, const T& valueO(n)1次(调用allocate(n))
范围构造InputIterator first, InputIterator lastO(N)(N为元素数)1次(随机访问迭代器)/多次(输入迭代器)
拷贝构造const vector& otherO(n)1次(other.capacity() >= other.size()时复用)
移动构造vector&& otherO(1)0次(转移现有存储)
构造函数异常安全性元素初始化方式是否需要析构原对象
填充值构造强异常安全(basic_guaranteed)逐个赋值(非构造)否(新建存储空间)
范围构造(普通迭代器)基本异常安全逐个拷贝构造否(新建存储空间)
强制指针构造无异常安全逐个拷贝构造是(销毁原数组)
构造函数分配器调用元素数量计算方式是否触发元素析构
默认构造
Allocator构造allocate(0)固定为0
移动构造无(复用源分配器)继承源vector.size()否(转移所有权)

通过对比可见,移动构造函数在性能上具有显著优势,但其异常安全性依赖于源对象的有效状态。填充值构造与范围构造的时间复杂度均为O(n),但后者可能因迭代器类型不同产生额外开销。默认构造与Allocator构造均不分配实际存储空间,但后者允许定制化内存管理策略。在选择构造函数时,需综合考虑性能需求、异常安全等级及内存管理要求。例如,在高性能场景下优先使用移动语义,而在需要严格异常安全时选择填充值构造或带异常规范的版本。