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

问题描述 投票:0回答:1

我想了解 Vector 或 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
c++ stl c++14
1个回答
0
投票

根据定义,复制赋值运算符将内容替换为源对象内容的副本。

具体来说,如果

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
对象的元素。因此,不会发生元素的赋值副本,而是发生在新内存中执行的构造副本,以及在旧内存中实例化的元素的销毁。

© www.soinside.com 2019 - 2024. All rights reserved.