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

std::vector范围初始化:预分配空间与直接拷贝构造的疑问

C++ vector 拷贝构造相关问题解析

测试代码

#include <utility>
#include <vector>
#include "iostream"

class Person {
public:
    std::string name{"no-name"};

    Person() {
        std::cout << std::string("Person()") << std::endl;
    }

    explicit Person(std::string name) : name(std::move(name)) {
        std::cout << std::string("Person(") + this->name + ")" << std::endl;
    }

    // operator =
    Person &operator=(const Person &other) {
        std::cout << std::string("operator= ") + other.name + "->" + this->name + "" << std::endl;
        return *this;
    }

    Person(const Person &other) noexcept {
        std::cout << std::string("copy ") + other.name + "->" + this->name + "" << std::endl;
        this->name = other.name;
    }

    // move
    Person(Person &&other) noexcept {
        std::cout << std::string("move ") + other.name + "->" + this->name + "" << std::endl;
        this->name = std::move(other.name);
    }

    ~Person() {
        std::cout << std::string("~Person(") + name + ")" << std::endl;
    }

};

int main() {

    std::cout << "construct person_list" << std::endl;
    std::vector<Person> person_list (4);

    std::cout << "construct person_list_copy" << std::endl;
    std::vector<Person> person_list_copy (person_list.begin(), person_list.end());
}

实际运行输出

construct person_list
Person()
Person()
Person()
Person()
construct person_list_copy
copy no-name->no-name
copy no-name->no-name
copy no-name->no-name
copy no-name->no-name
~Person(no-name)
~Person(no-name)
~Person(no-name)
~Person(no-name)
~Person(no-name)
~Person(no-name)
~Person(no-name)
~Person(no-name)

预期输出

construct person_list
Person()
Person()
Person()
Person()
construct person_list_copy
Person()
Person()
Person()
Person()
copy no-name->no-name
copy no-name->no-name
copy no-name->no-name
copy no-name->no-name
~Person(no-name)
~Person(no-name)
~Person(no-name)
~Person(no-name)
~Person(no-name)
~Person(no-name)
~Person(no-name)
~Person(no-name)

疑问解答

1. vector对象person_list_copy在执行拷贝构造操作前,足够的内存空间从何而来?

vector内部会先通过内存分配器(默认是std::allocator<Person>)申请一块能容纳4个Person对象的原始内存,这个过程只分配内存,不会调用任何Person的构造函数。内存分配器底层类似malloc,但封装成了C++标准库的组件,专门为容器服务。

2. 为何没有先调用默认构造创建预构造单元,而是直接调用拷贝构造?

这是因为你用了vector的范围构造函数(std::vector(InputIterator first, InputIterator last)),这个构造函数的逻辑是:

  • 先计算迭代器范围内的元素数量(这里是4个),用分配器申请对应大小的原始内存。
  • 然后遍历输入范围,对每个元素,直接在已分配的原始内存上原地构造新的Person对象——也就是调用Person的拷贝构造函数,把原vector里的对象复制到新内存的对应位置。

你之前的理解是把vector当成“先创建空对象再赋值”,那是另一种场景(比如用resize然后逐个赋值)。而范围构造函数跳过了默认构造+赋值的步骤,直接在目标内存上拷贝构造,效率更高,这是C++容器针对批量元素初始化做的优化。

用底层术语解释的话,这个过程用到了定位new表达式(placement new):分配器拿到原始内存地址后,调用new (ptr) Person(other),直接在ptr指向的内存上构造Person对象,不需要先创建默认构造的对象再覆盖。

内容的提问来源于stack exchange,提问作者strider aron

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 02:45:25