c++ STL容器如何处理赋值运算符

np8igboo  于 2023-05-08  发布在  其他
关注(0)|答案(1)|浏览(132)

我想了解矢量或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
a6b3iqyw

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对象。

相关问题