添加和初始化新std::map元素的最有效方法是什么

What is the most efficient way to add and initialize a new std::map element?

本文关键字:有效 是什么 方法 元素 map 初始化 std 添加      更新时间:2023-10-16

假设,如果我有以下映射,其中每个元素都包含一个数组:

struct STRUCT{
int value;
std::vector<MY_DATA> myArr;
};
std::map<UINT, STRUCT> myMap;

然后,如果我想在映射中添加一个新元素,同时初始化它:

//But, let's say we have a 'STRUCT' with a large number of items in the vector
std::vector<MY_DATA> arr;
arr.resize(0x10000);        //Arbitrary
int val = 123;
addToMap(&arr, val);

据我所知,我有以下方法可以做到这一点:

void addToMap1(UINT id, std::vector<MY_DATA>* pArr, int val)
{
//Method 1
STRUCT myStruct;
myStruct.myArr = *pArr;
myStruct.value = val;
myMap[id] = myStruct;
}
void addToMap2(UINT id, std::vector<MY_DATA>* pArr, int val)
{
//Method 2
myMap[id] = STRUCT();
STRUCT* pS = &myMap[id];
pS->myArr = *pArr;
pS->value = val;
}
void addToMap3(UINT id, std::vector<MY_DATA>* pArr, int val)
{
//Method 3
myMap[id] = STRUCT();
std::map<UINT, STRUCT>::iterator itr = myMap.find(id);
STRUCT* pS = &itr->second;
pS->myArr = *pArr;
pS->value = val;
}
void addToMap4(UINT id, std::vector<MY_DATA>* pArr, int val)
{
//Method 4
std::pair<std::map<UINT, STRUCT>::iterator, bool> prNew = 
myMap.insert(std::pair<UINT, STRUCT>(id, STRUCT()));
ASSERT(prNew.second);       //It must have not existed before!  
STRUCT* pS = &prNew.first->second;
pS->myArr = *pArr;
pS->value = val;
}

但最有效的方法是什么?

如果您的意图意味着覆盖地图中已经存在的密钥的现有数据,那么只需普通

void addToMap(UINT id, const std::vector<MY_DATA>* pArr, int val)
{
STRUCT &pS = myMap[id];
pS.value = val;
pS.myArr = *pArr;
}

会非常有效地完成这个把戏。目前尚不清楚为什么在现有的"方法"中,您坚持首先将默认构造的STRUCT()保存到myMap[id]中。这是完全没有必要的。

其他优化机会包括:

  1. 从现有矢量移动数据,而不是复制数据(如果可能)
  2. 甚至不构建源向量,而是直接在地图中构建目标向量(如果可能的话)
  3. 如果源向量需要作为一个独立的对象存在(并且是长寿命的),那么指向该向量的指针可以存储在映射中,而不是完整的副本

但从您的描述中不清楚这是否适用于您的情况。


请注意,您不能将emplace用于此目的,因为emplace在这种情况下不会执行您想要执行的操作:它不会覆盖现有密钥的数据。在这种情况下,我们需要的是insert_or_assign的转发版本,但遗憾的是,它并不存在。

您可以移动资源,比如:

void addToMap(UINT id, std::vector<MY_DATA>&& arr, int val)
{
auto& s = myMap[id];
s.myArr = std::move(arr);
s.value = val;
}