Каков наиболее эффективный способ добавить и инициализировать новый элемент std :: map? - PullRequest
0 голосов
/ 09 января 2019

Скажите, если у меня есть следующая карта, где каждый элемент содержит массив:

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;
}

Но какой самый эффективный способ сделать это?

Ответы [ 2 ]

0 голосов
/ 09 января 2019

Если ваше намерение подразумевает перезапись существующих данных для ключа, который уже присутствует на карте, то просто введите

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, но, увы, ее не существует.

0 голосов
/ 09 января 2019

Вы можете переместить ресурс, что-то вроде:

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