我想了解矢量或UnorderedMap的ie复制赋值运算符后面指定的语义。是否在某个地方说明了将对该操作执行什么操作(或者是否定义了实现)?也就是说,它是否会在存储的数据上触发复制赋值,或者?简单的程序表明,在复制分配的情况下,STL似乎做复制构造+旧条目的销毁。示例:
#include <iostream>
#include <array>
#include <bitset>
#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
1条答案
按热度按时间a6b3iqyw1#
作为定义,复制赋值操作符用源对象内容的副本替换内容。
但是,如果您的代码至少使用C++11,则需要添加关于复制赋值运算符如何工作的更多描述。特别地,如果std::allocator_traits<allocator_type>::propagate_on_container_copy_assignment别名为true,并且std::allocator_traits<allocator_type>::is_aleays_equal别名为false,则目标分配器被源分配器的副本替换。如果目标分配器和源分配器比较不相等,则目标分配器用于释放内存,然后源分配器用于在复制元素之前分配内存。否则,由目标容器拥有的存储器可以在可能时被重用。
您在测试中遇到的行为是由于误解了“内存可能会被重用”这句话,这句话暗示当要从源容器复制的元素数量大于目标容器的容量时,可能需要重新分配内存,而其他容器可能有更严格的规则。例如,
std::unordered_map
容器在加载因子超过其上限时可能需要重新分配。无论如何,由于管理增长因子的实现,
bla2
对象的容量每次只增加一个单位,不足以包含bla
对象的元素。由于这个原因,不发生元素的赋值复制,而是在新存储器中执行的构造复制,以及在旧存储器中示例化的元素的销毁。当然,在新的重新分配和新的构造已经成功执行之前,元素不被破坏并且存储器不被解除分配,以在异常的情况下保证更好的稳定性。顺便说一句,您错误地使用了
emplace_back()
成员函数,因为您在将其传递给函数之前执行了临时TypeA
对象的构造,而上面的函数就是为了避免这种情况而专门设计的。您应该不向emplace_back()
成员函数传递任何参数,该函数将就地构造TypeA
对象。