эффективный способ вставить unique_ptr в карту без удаления указателя, если ключ уже существует

Легкий путь очевиден

std::map<int,std::unique_ptr<something>> mymap;

auto f = mymap.find(5);
std::unique_ptr<something> myptr;

if (f == mymap.end())
    mymap.insert({5, std::move(myptr)});

Однако это выглядит не слишком эффективно, так как мне приходится дважды искать ключ на карте. Один, чтобы проверить, не существует ли ключ, и функция вставки также сделает то же самое.

Если я просто использую mymap.insert({5, std::move(myptr)});, то мой уникальный ptr (myptr) исчезнет, ​​если pair.second вернет false (ключ уже существует).

РЕДАКТИРОВАТЬ:

По-видимому, ответ на С++ 17 с try_emplace, и он уже доступен в компиляторе, который я использую (vs2015), и, поскольку я работаю над личным проектом, я могу позволить себе его использовать.


person Gam    schedule 10.06.2016    source источник
comment
Почему вы говорите, что это не выглядит эффективным? Выглядит хорошо для меня.   -  person Russley Shaw    schedule 10.06.2016
comment
Если вас беспокоит сложность std::map::find, возможно, вы используете не тот контейнер? std::unordered_map находится поверх хеш-таблицы, поэтому некоторые операции амортизируются за O(1) вместо O(log n) — поиск включен.   -  person Conduit    schedule 10.06.2016
comment
Похоже, вы хотите, чтобы в следующем стандарте появился try_emplace.   -  person NathanOliver    schedule 10.06.2016
comment
Это похоже на проблему XY: вы задаете нам вопрос о решении, которое у вас есть, и хотите, чтобы его решили, но вы не говорите нам проблему, которую вы на самом деле пытаетесь решить.   -  person Some programmer dude    schedule 10.06.2016
comment
@NathanOliver Спасибо за это. Прежде чем создать этот вопрос, я искал функцию try_, но не в том месте (cplusplus.com).   -  person Gam    schedule 10.06.2016


Ответы (3)


Если вы не собираетесь хранить nullptr на своей карте, вы можете сделать это следующим образом:

auto& r = mymap[5];
if ( r == nullptr )
    r = std::move(myptr);
person Leon    schedule 10.06.2016
comment
Это очень интересная идея! - person Gam; 10.06.2016

Стандартный прием заключается в поиске точки вставки:

auto f = mymap.lower_bound(5);
if ((f == mymap.end()) || mymap.key_comp()(5, f->first)) {
    mymap.insert(f, {5, std::move(myptr)}); // or mymap.emplace_hint(f, 5, std::move(myptr))
}
person Joshua Green    schedule 10.06.2016

Может быть, я не совсем понимаю контекст, но зачем что-то перемещать, а не ставить?

std::map<int,std::unique_ptr<something>> mymap;

auto f = mymap.find(5);

if (f == mymap.end()) 
    mymap.emplace(5, std::make_unique<something>(myptr));
person Jan Korous    schedule 10.06.2016
comment
Это по-прежнему выполняет поиск дважды, как и исходный фрагмент OP. - person Ilya Popov; 11.06.2016