STL容器(Vector/UnorderedMap)拷贝赋值运算符语义规范探究
STL容器拷贝赋值运算符的语义规范解析
核心问题
想搞清楚vector、unordered_map这类STL容器的拷贝赋值运算符(operator=(const Container&))背后的语义规范:
- 该操作的行为是由C++标准明确规定,还是属于实现定义?
- 它是否会触发存储元素的拷贝赋值?
通过测试发现,STL容器执行拷贝赋值时,似乎会先拷贝构造新元素,再销毁原有元素,以下是测试代码及运行结果:
测试代码
#include <iostream> #include <vector> #include <unordered_map> using namespace std; struct TypeA { TypeA() {} TypeA(const TypeA& a) { std::cout << "Copy ctor " << std::endl; } TypeA(TypeA&& a) { std::cout << "move ctor " << std::endl; } TypeA& operator=(const TypeA& a) { std::cout << "Copy assigment " << std::endl; return *this; } TypeA& operator=(TypeA&& a) { std::cout << "move assigment " << std::endl; return *this; } ~TypeA() { std::cout << "dtor" << std::endl; } }; int main() { std::vector<TypeA> bla; bla.emplace_back(TypeA{}); bla.emplace_back(TypeA{}); bla.emplace_back(TypeA{}); std::vector<TypeA> bla2; bla2.emplace_back(TypeA{}); bla2.emplace_back(TypeA{}); std::cout << "Start TEST" << std::endl; bla2 = bla; std::cout << "END TEST" << std::endl; return 0; }
运行结果
... Start TEST Copy ctor Copy ctor Copy ctor dtor dtor ... END TEST
语义规范与行为解析
行为是C++标准明确规定的,并非实现定义。标准要求拷贝赋值后,目标容器必须成为源容器的完全副本:
- 目标容器的大小与源容器一致;
- 目标容器的每个元素都是源容器对应元素的拷贝(满足
element == source_element); - 源容器的状态不会被修改。
具体执行逻辑的差异(符合标准的实现选择):
标准只定义了最终效果,具体实现可以选择不同的执行路径,常见的两种方式:- 直接原地修改:如果目标容器的容量(如
vector的capacity())大于等于源容器的大小,会先对现有元素中与源容器数量匹配的部分执行拷贝赋值,再销毁目标容器中多余的元素(若目标原大小更大);若源容器更大,则会在目标容器末尾拷贝构造额外的元素。 - Copy-and-Swap惯用法:很多STL实现会采用这种方式,先拷贝构造一个临时容器(对应测试中的三次
Copy ctor),再将临时容器与目标容器交换内部数据,最后临时容器销毁时带走目标容器原来的元素(对应测试中的两次dtor)。这种方式简洁且能保证异常安全,完全符合标准语义。
- 直接原地修改:如果目标容器的容量(如
关于
unordered_map等关联容器:
关联容器的拷贝赋值语义与序列容器一致——目标容器会成为源容器的副本,每个键值对都会被拷贝。实现上同样可能采用类似的Copy-and-Swap,或者逐个拷贝键值对并替换原有元素。
内容的提问来源于stack exchange,提问作者Pawel Rutka
相关产品推荐
相关产品推荐

