LINUX.ORG.RU

std::unordered_map + emplace + non-movable тип

 


0

3

Допустим, мы хотим хранить в качестве значений в unordered_map неперемещаемый тип. Например, вот так:

#include <mutex>
#include <unordered_map>

struct MyStruct {
    std::mutex mutex;
    int data = 0;
};

void f(std::unordered_map<int, MyStruct> &map, int key) {
    map.emplace(key, {});
}

Получаем ошибку компиляции: https://godbolt.org/z/vaTc5rxfP

У std::mutex нет ни конструктора копирования, ни конструктора перемещения. Однако, такие типы допустимо хранить в качестве значений в данном типе контейнера, потому что под капотом происходит динамическое выделение памяти и контейнер гарантирует, что единственная операция инвалидирующая ссылки и указатели на элементы - erase. Значит за всё время жизни элемента его никто никуда не переместит.

Проблема в том, как сделать emplace. Если бы у MyStruct был конструктор с аргументами - всё было бы просто. А у MyStruct нет конструктора, либо можно добавить, но по логике программы имеет смысл лишь конструктор без аргументов. Однако передать пустой список аргументов в emplace я не могу.

★★★★★

передать пустой список аргументов в emplace я не могу.

Кто мешает?

Используй std::piecewise_construct, чтобы передать в конструктор std::pair пустой список аргументов для одного из объектов: 8 вариант.

lwo
()
Последнее исправление: lwo (всего исправлений: 2)

Осталось понять почему претензия к неперемещаемости, если без мьютекса:

#include <unordered_map>

struct MyStruct {
    int data;
};

void f(std::unordered_map<int, MyStruct> &map, int key) {
    map.emplace(key, {});
}

не компилируется с такой же ошибкой, как с ним.

utf8nowhere ★★★
()
Ответ на: комментарий от slackwarrior

У мапы есть свой mutex. Блокируешь мапу, находишь/создаёшь объект, блокируешь уже его персональный мьютекс, разблокируешь мапу и работаешь уже только с самим объектом. Таким образом разные потоки могут одновременно обрабатывать разные объекты хранящиеся в одной мапе. Кстати, самой мапе можно shared_mutex, тогда операция поиска тоже будет конкурентной (только для вставки и удаления придётся захватывать мапу монопольно, а для удаления ещё и персональный mutex удаляемого объекта).

Специфика unordered_map такова, что ссылки и указатели на элементы не инвалидируются при её модификации (кроме единственной операции удаления элемента).

KivApple ★★★★★
() автор топика
Последнее исправление: KivApple (всего исправлений: 1)
Ответ на: комментарий от KivApple

Барочный дизаен эт итс бест :) обычно чем больше точек синкания, тем больше намеков что с параллельностью что-то не так. Да оп-пост содержит в себе часть ответа: если граблей больше чем выгод, нужно убедиться, а может просто не предполагалось подобного использования? Когда такие вопросы возникают, может проще пересмотреть дизаен.

slackwarrior ★★★★★
()
Последнее исправление: slackwarrior (всего исправлений: 2)