Вызов неявно удаленного конструктора копирования при использовании интеллектуального указателя с std::map()

Я пытаюсь поместить объект класса в std::map, и возникает ошибка. Вот код:

классы.hpp

#ifndef CLASSMETHODNOTCALLED_CLASSES_HPP
#define CLASSMETHODNOTCALLED_CLASSES_HPP

#include "iostream"
#include "memory"

// tow classes with one pointing to the other

class Ca
{
    int m_va = 5;
public:
    Ca();
    int getVa();
};


class Cb
{
    std::unique_ptr<Ca> m_x; // a smart ptr pointing to class Ca
    int m_vb;
public:
    explicit Cb(int n);
    ~Cb();
    int getCa();
};
#endif //CLASSMETHODNOTCALLED_CLASSES_HPP

классы.cpp

#include "../include/classes.hpp"
#include "memory"

// Ca
Ca::Ca()
{

}

int Ca::getVa()
{
    return m_va;
};

// Cb
Cb::Cb(int n)
{
    m_x = std::make_unique<Ca>();
    m_vb = n;
}

Cb::~Cb()
{
}

int Cb::getCa()
{
    return m_x->getVa() + m_vb; // returns 5 + 1 = 6 if works properly
}

main.cpp

#include <iostream>
#include "include/classes.hpp"
#include "map"

int main()
{
    Cb cb(1);  // instanciate Cb

    std::map<int, Cb> m;
    m.emplace(1, cb); // the line where it complains: Call to implicitly deleted copy constructor
    int i = m.at(1).getCa(); // should return 6 if working properly

//    int i = cb.getCa(); // code without using std::map() works

    std::cout << "va = " << i << std::endl;
}

Я думаю, что это вызвано умным указателем, конструктор которого явно удален. Мой вопрос: как в этом случае вставить cb в std::map()? Спасибо!

ОБНОВЛЯТЬ:

Сейчас я пытаюсь получить с карты объект Cb, и вот что я сделал

int main()
{
    Cb cb(1);  // instanciate Cb

    std::map<int, Cb> m;
    m.emplace(1, std::move(cb));

    Cb ccb = m.at(1); // error occurs here complaining Call to implicitly deleted copy constructor
    int i = m.at(1).getCa();

//    int i = cb.getCa();

    std::cout << "va = " << i << std::endl;
}

Есть идеи?

m.emplace(1, std::move(cb)). Но, как говорится, содержимое будет перемещено на карту. cb.m_x после этого будет пустым. Весь смысл unique_ptr в том, чтобы быть уникальным, то есть не поддающимся копированию, чтобы два экземпляра ссылались на один и тот же управляемый объект.
user17732522 23.08.2024 15:49

unique_ptr или класс с таким членом нельзя скопировать, его необходимо явно переместить. Если его скопировать, он больше не уникален!

BoP 23.08.2024 15:49

Кроме того, почему m_x — это unique_ptr<Ca>, а не просто Ca? Я не вижу для этого никаких причин.

user17732522 23.08.2024 15:50

А ваш класс нарушает правило 0/3/5. Если ваш деструктор будет определен как пустой, то его вообще не следует объявлять, чтобы следовать правилу нуля.

user17732522 23.08.2024 15:51
#include "iostream" и т. д. тоже неверно. Заголовки стандартной библиотеки гарантированно будут работать правильно, только если они включены в </>.
user17732522 23.08.2024 15:51
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
6
51
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

emplace принимает параметры и передает их конструктору элемента карты. Если вы передадите ему Cb, он скопирует его, если вы передадите ему ссылку на rvalue, он переместит его, а если вы передадите 1, он будет использовать это для создания Cb.

Следовательно, вы можете

  • добавьте конструктор перемещения в Cb (Cb(Cb&&)=default; или, скорее, удалите деструктор, тогда компилятор сможет сгенерировать оба) и выполните

    m.emplace(1,std::move(cb));
    
  • или постройте Cb на месте

    m.emplace(1,1);
    

Но вы не можете попросить emplace скопировать Cb, потому что Cb не имеет конструктора копирования.

К сожалению, поскольку OP без необходимости объявляет деструктор, это не будет работать автоматически с их кодом из-за отсутствия неявных операций перемещения.

user17732522 23.08.2024 15:56

@user17732522 user17732522 да, их нужно будет добавить, поэтому я написал «добавить конструктор перемещения», тогда все работает godbolt.org/z/sj44Krxvr.

463035818_is_not_an_ai 23.08.2024 15:57

Ой, извини. Наверное, пропустил эту часть при чтении.

user17732522 23.08.2024 15:57

Cb (Cb(Cb&&) = по умолчанию; кажется, не работает?

Nick X Tsui 23.08.2024 16:05

@NickXTsui да, так и есть. Почему нет?

463035818_is_not_an_ai 23.08.2024 16:05

@NickXTsui, у тебя слишком много Cb. предложение гласит: «Добавьте конструктор перемещения в открытую скобку Cb, вот как это выглядит: Cb(Cb&&)= default; закрывающая скобка»

463035818_is_not_an_ai 23.08.2024 16:06

@ 463035818_is_not_an_ai под значением по умолчанию есть красное покачивание, которое гласит: «По умолчанию могут использоваться только специальные функции-члены».

Nick X Tsui 23.08.2024 16:07

@ 463035818_is_not_an_ai Хорошо, теперь все работает. Большое спасибо!

Nick X Tsui 23.08.2024 16:08

@ 463035818_is_not_an_ai `Можно ли как-нибудь посмотреть раздел обновлений в исходном сообщении? Я пытаюсь извлечь объект с карты, а компилятор жалуется на это. Не знаю, как с этим справиться. Большое спасибо!!

Nick X Tsui 23.08.2024 16:23

@NickXTsui, пожалуйста, не меняйте вопрос, чтобы задать что-то еще после получения ответов. Вы можете открыть новый вопрос (и вам следует удалить обновление здесь)

463035818_is_not_an_ai 23.08.2024 16:44

std::unique_ptr можно перемещать, но не копировать.

Сначала создайте конструктор/оператор перемещения.

class Cb
{
    std::unique_ptr<Ca> m_x; // a smart ptr pointing to class Ca
    int m_vb;
public:
    explicit Cb(int n);
    Cb(Cb&& other) = default;
    Cb& operator=(Cb&& other) = default;
    ~Cb();
    int getCa();
};

И теперь вы можете переместить свой Cb:

m.emplace(1, std::move(cb));

Обратите внимание, что m_x экземпляра Cb, из которого вы переместились, станет нулевым.

Чтобы получить элемент, вы должны использовать ссылку:

Cb& elem = map[i];

Определение операций перемещения вручную — неправильный подход. Гораздо более целесообразным было бы следовать правилу нуля. Даже если вы определяете их самостоятельно, они должны быть заданы по умолчанию.

user17732522 23.08.2024 15:54

экземпляр, перемещенный из экземпляра, не станет «недействительным». У него будет m_x, у которого больше нет Ca, но в остальном все в порядке Cb

463035818_is_not_an_ai 23.08.2024 16:01

в этой части кода, похоже, возникла проблема: Cb&operator=(Cb&&other) {} m_vb =other.m_vb; m_x = std::move(other.m_x); верните это;

Nick X Tsui 23.08.2024 16:02

@ 463035818_is_not_an_ai Я ничего не говорил о том, что Cb является инвалидом. Только m_x. Хотя «инвалидный» — это, возможно, расплывчатый термин.

DatGeoudon 24.08.2024 01:44

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