为何vector元素拷贝可使用非const左值参数?拷贝时调用何种构造函数?
std::vector元素拷贝的构造函数调用相关问题
问题
- 为何
std::vector的元素拷贝可以使用非const左值参数? - 复制
std::vector、调用reserve(扩容)或shrink_to_fit(缩容)时,元素类型会调用哪个构造函数? - 若调用了非const左值构造函数,是否可认为用户代码允许(至少临时)修改其参数?
示例代码
#include <vector> #include <iostream> struct A { A() {} A(A&) { std::cout << "A(A&) "; } A(const A&) { std::cout << "A(const A&) "; } }; int main() { std::vector<A> v(1); v.reserve(10); auto w = v; v.shrink_to_fit(); }
各标准库实现的输出差异
预期输出为A(const A&) A(const A&) A(const A&),但不同实现结果不同:
- libc++:
A(const A&) A(A&) A(const A&) - libstdc++:
A(const A&) A(const A&) A(A&) - Microsoft STL:
A(A&) A(A&) A(A&)
解答
1. 非const左值参数的使用依据
C++标准并未强制要求std::vector在拷贝元素时必须使用const左值版本的拷贝构造函数。当源元素是可修改的左值(比如非const的vector对象中的元素)时,标准库实现有权选择调用非const的拷贝构造函数——只要该构造函数存在。这是因为标准允许容器根据元素的可访问性,选择最匹配的构造函数完成拷贝操作。
2. 不同操作的构造函数选择
复制、reserve、shrink_to_fit这三个操作都涉及元素的内存迁移/拷贝,但具体调用哪个构造函数取决于标准库的实现细节:
reserve:扩容时需要将旧内存的元素拷贝到新内存,此时源元素属于非const的vector对象,部分实现会优先匹配非const拷贝构造函数。- 复制vector:源vector是可修改左值,实现可选择调用非const或const版本的拷贝构造函数。
shrink_to_fit:缩容时的元素拷贝逻辑与扩容类似,源元素的可修改性可能导致实现选择非const构造函数。
标准仅要求这些操作完成元素的正确拷贝,未严格限定构造函数的版本,因此不同实现会出现差异。
3. 非const构造函数的语义
是的。当用户提供了非const左值拷贝构造函数A(A&),就等同于向编译器和标准库传递了一个信号:该构造函数允许修改传入的源对象。标准库调用这个构造函数时,默认假设用户代码接受这种修改——哪怕构造函数内部并没有实际修改源对象。如果不希望源对象被修改,应该只提供const版本的拷贝构造函数,或者显式delete非const版本。
内容的提问来源于stack exchange,提问作者Fedor
相关产品推荐
相关产品推荐

