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
相关产品推荐
相关产品推荐

