Как вставить элементы в контейнер std::vector<std::map<int, std::unique_ptr<int>>>?

У меня есть контейнер std::vector<std::map<int, std::unique_ptr<int>>> (если упростить). Изначально я должен вставить в std::vector некоторое количество std::map, у каждого из них будет по одной паре ключ-значение. Я пробовал такой код:

#include <iostream>
#include <map>
#include <vector>
#include <memory>

using namespace std;

int main()
{
    vector<map<int, std::unique_ptr<int>>> data{};

    for (int x = 0; x < 10; x++)
    {
        data.emplace_back(std::make_pair(x, std::make_unique<int>(x)));
    }
}

Но это не сработало. Как я могу изменить его, чтобы он работал так, как ожидалось?

Обновлено: я понял свою ошибку, мне пришлось использовать этот фрагмент кода, чтобы добавить элемент:

std::map<int, std::unique_ptr<int>> m;
m.emplace(x, std::make_unique<int>(y));
data.emplace_back(std::move(m));

Тогда код будет работать в онлайн-компиляторах, но по-прежнему не работает в Visual Studio.

Вам нужно скормить std::map<int, std::unique_ptr<int>> в data.emplace_back(...), а не пару int и unique_ptr<int>

chrysante 14.06.2023 14:32

Также stackoverflow.com/questions/1452721/…

chrysante 14.06.2023 14:34

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

john 14.06.2023 14:36

Я знаю, я не использую using namespace std; в своем проекте, это минимально воспроизводимый пример. Также пытался вставить так: data.emplace_back(map<int, std::unique_ptr<int>>{ std::make_pair(x, std::make_unique<int>(x)) }); но не получилось

Roman Leshchuk 14.06.2023 14:36

Проблема заключается в построении карты без копирования типа значения, которое из-за unique_ptr не может быть скопировано. Как бы вам явно ни нравилось писать минимальный код, который делает очень много с очень небольшими затратами, в этом случае, я думаю, вам просто придется разбить код на более мелкие шаги.

john 14.06.2023 14:53

«Изначально я должен вставить в std::vector некоторое количество std::map» — Ваши собственные слова: где в вашей программе есть код, который вообще создает какие-либо std::map? Как вы думаете, что std::map нужно вставить в вектор и почему? Можете ли вы показать код, который создаст такой std::map? Где код говорит std::make_pair(x, std::make_unique<int>(x)), как вы думаете, что за вещь создается этим кодом? Имеет ли смысл хранить это на карте? Что, если вы попытаетесь иметь карту и использовать что-то подобное для ввода данных в карту, а затем поместить карту в вектор?

Karl Knechtel 14.06.2023 15:02

«Но это не сработало. Как я могу изменить его, чтобы он работал как положено?» Это не ясный вопрос, потому что вы не описываете, что произошло, и вы не описываете, что вместо этого должно произойти. Это тоже бесполезный вопрос, потому что решить его вам мешает не недостаток знаний или понимания, а недостаток внимания и анализа.

Karl Knechtel 14.06.2023 15:03
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
7
56
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Причина вашей ошибки в том, что emplace_back попытается создать map в vector, например:

std::map<int, std::unique_ptr<int>>(std::make_pair(...))

См. также: конструкторы std::map

Однако это невозможно, потому что конструктор, принимающий пары, принимает std::initializer_list<std::pair<K, V>>. Не существует конструктора, который принимает одну пару. Правильный способ:

map<int, unique_ptr>{std::make_pair(...)}

Однако конструкторы, использующие std::initializer_list<T>, требуют, чтобы T был копируемым, а std::unique_ptr<int> не копируемым, поэтому содержащий T = std::pair<int, std::unique_ptr<int>> также не копируемый. Это оставляет нам следующее решение:

#include <iostream>
#include <map>
#include <vector>
#include <memory>

int main()
{
    using map_type = std::map<int, std::unique_ptr<int>>;

    std::vector<map_type> data{};

    for (int x = 0; x < 10; x++)
    {
        for (int y = 0; y < 10; y++)
        {
            map_type m;
            m.emplace(x, std::make_unique<int>(y));
            data.emplace_back(std::move(m));
        }
    }
}

Смотрите живой пример

Проблемы с Visual Studio

В стандартной библиотеке MSVC невозможно использовать std::vector<std::map<int, std::unique_ptr<int>>. Причина в том, что из-за строгих гарантий исключений std::vector требует, чтобы тип его элемента был std::nothrow_move_constructible или копировальным.

Вы можете видеть, что в MSVC STL, std::map имеет не-noexcept конструктор перемещения:

map(map&& _Right) : _Mybase(_STD move(_Right)) {}

Вот быстрое и грязное решение этой проблемы:

template <typename K, typename V>
struct nothrow_map : std::map<K, V> {
    nothrow_map() = default;
    nothrow_map(nothrow_map&& other) noexcept : std::map<K, V>(std::move(other)) {}
};

// ...

using map_type = nothrow_map<int, std::unique_ptr<int>>;

См. также: std::move_if_noexcept (используется std::vector внутренне)

Прошу прощения, но этот код у меня не работает

Roman Leshchuk 14.06.2023 14:41
Error C2280 'std::pair<const int,std::unique_ptr<int,std::default_delete<int>>>::pair(con‌​st std::pair<const int,std::unique_ptr<int,std::default_delete<int>>> &)': attempting to reference a deleted function. Я использую Visual Studio, С++ 20.
Roman Leshchuk 14.06.2023 14:45

Это странно, потому что он работает в онлайн-компиляторах, а тот же код не работает в Visual Studio.

Roman Leshchuk 14.06.2023 14:50

Хорошо, спасибо за объяснение. Но я все равно не вижу смысла вводить такое ограничение

Roman Leshchuk 14.06.2023 15:08

@JanSchultke Хорошая работа, если бы я мог дать этому ответу более одного голоса, я бы это сделал.

john 14.06.2023 15:10

@RomanLeshchuk ответ теперь включает грязное исправление. Он работает, наследуя от std::map и предоставляя производному типу nothrow_map конструктор перемещения noexcept. Это грязно, но вряд ли когда-нибудь выйдет из строя, поскольку в этом случае конструктор перемещения std::map выдаст только ошибку выделения, а это маловероятно.

Jan Schultke 14.06.2023 15:10

Другие вопросы по теме