Как правильно выделить и освободить карту векторов - PullRequest
0 голосов
/ 20 марта 2020

Я пытаюсь сохранить данные в неупорядоченной карте векторов, используя адреса uint32_t в качестве ключей. Вектор должен быть сохранен в куче, чтобы я мог получить доступ к данным, даже если функция выходит из области видимости. Я сделал распределение следующим образом:

using vectorBuffer = std::vector<uint8_t>;
using I2cVectorMap = std::unordered_map<address_t, vectorBuffer>;
using I2cVectorEntry = std::pair<address_t, vectorBuffer>;

if(auto i2cIter = i2cVectorMap.find(address); i2cIter == i2cVectorMap.end()) {
    vectorBuffer * receiveVector = new vectorBuffer(maxReplyLen);
    i2cVectorMap.insert(I2cVectorEntry(address, *receiveVector));
}
else {
    // Already in map. readjust size
    vectorBuffer * existingVector = &i2cIter->second;
    existingVector->resize(maxReplyLen);
    existingVector->shrink_to_fit();
}

И такое освобождение (как рекомендовано различными источниками, заменяя вектор на пустой):

// getting the address from another object.
address_t deviceAddress = i2cCookie->getAddress();
if(auto i2cIter = i2cVectorMap.find(deviceAddress); i2cIter != i2cVectorMap.end()) {
    vectorBuffer().swap(i2cIter->second);
}

это правильно реализация? Я передам адрес записи карты либо функции драйвера, инициирующей передачу I2 C, либо другому объекту, обрабатывающему данные. Я хочу убедиться, что у меня нет утечки памяти.

Заранее большое спасибо!

1 Ответ

3 голосов
/ 20 марта 2020

Нет, вы не должны использовать new. Во-первых, случаи, когда требуются прямые new s, редки.

Вам не нужно создавать объекты с динамическим c сроком хранения («в куче») вручную. Контейнеры стандартной библиотеки хранят объекты непосредственно , а не ссылки или указатели на объекты. Они будут выделять для этих объектов и строить их самостоятельно. Вы предоставляете аргументы конструктора только функциям-членам контейнера, из которых контейнер (копирование / перемещение) создает хранимые элементы.

Вы можете просто объявить объект как автоматическую c переменную (то есть "в стеке") ):

vectorBuffer receiveVector(maxReplyLen);
i2cVectorMap.insert(I2cVectorEntry(address, receiveVector));

или использовать временный для промежуточного экземпляра вектора вместо именованной переменной (это также будет использовать перемещение вместо операции копирования и, следовательно, лучше для производительности):

i2cVectorMap.insert(I2cVectorEntry(address, vectorBuffer(maxReplyLen)));

и если вы используете emplace вместо insert, вы также можете удалить тип резервированной пары:

i2cVectorMap.emplace(address, vectorBuffer(maxReplyLen));

Вам не нужен указатель для вызова методов на объект на карте:

vectorBuffer& existingVector = i2cIter->second;
existingVector.resize(maxReplyLen);
existingVector.shrink_to_fit();

И для удаления элемента с карты вы используете .erase функцию-члена:

i2cVectorMap.erase(deviceAddress);

Вам не нужно делать что-нибудь еще. Это также разрушит и освободит вектор.

Когда вам больше не нужна карта и векторы, которые в ней содержатся, вам также ничего не нужно делать. Деструктор карты очистит все автоматически, когда область, в которой определена карта, оставлена.

...