Я пытаюсь поместить объект класса в 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;
}
Есть идеи?
unique_ptr или класс с таким членом нельзя скопировать, его необходимо явно переместить. Если его скопировать, он больше не уникален!
Кроме того, почему m_x — это unique_ptr<Ca>, а не просто Ca? Я не вижу для этого никаких причин.
А ваш класс нарушает правило 0/3/5. Если ваш деструктор будет определен как пустой, то его вообще не следует объявлять, чтобы следовать правилу нуля.
#include "iostream" и т. д. тоже неверно. Заголовки стандартной библиотеки гарантированно будут работать правильно, только если они включены в </>.





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 user17732522 да, их нужно будет добавить, поэтому я написал «добавить конструктор перемещения», тогда все работает godbolt.org/z/sj44Krxvr.
Ой, извини. Наверное, пропустил эту часть при чтении.
Cb (Cb(Cb&&) = по умолчанию; кажется, не работает?
@NickXTsui да, так и есть. Почему нет?
@NickXTsui, у тебя слишком много Cb. предложение гласит: «Добавьте конструктор перемещения в открытую скобку Cb, вот как это выглядит: Cb(Cb&&)= default; закрывающая скобка»
@ 463035818_is_not_an_ai под значением по умолчанию есть красное покачивание, которое гласит: «По умолчанию могут использоваться только специальные функции-члены».
@ 463035818_is_not_an_ai Хорошо, теперь все работает. Большое спасибо!
@ 463035818_is_not_an_ai `Можно ли как-нибудь посмотреть раздел обновлений в исходном сообщении? Я пытаюсь извлечь объект с карты, а компилятор жалуется на это. Не знаю, как с этим справиться. Большое спасибо!!
@NickXTsui, пожалуйста, не меняйте вопрос, чтобы задать что-то еще после получения ответов. Вы можете открыть новый вопрос (и вам следует удалить обновление здесь)
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];
Определение операций перемещения вручную — неправильный подход. Гораздо более целесообразным было бы следовать правилу нуля. Даже если вы определяете их самостоятельно, они должны быть заданы по умолчанию.
экземпляр, перемещенный из экземпляра, не станет «недействительным». У него будет m_x, у которого больше нет Ca, но в остальном все в порядке Cb
в этой части кода, похоже, возникла проблема: Cb&operator=(Cb&&other) {} m_vb =other.m_vb; m_x = std::move(other.m_x); верните это;
@ 463035818_is_not_an_ai Я ничего не говорил о том, что Cb является инвалидом. Только m_x. Хотя «инвалидный» — это, возможно, расплывчатый термин.
m.emplace(1, std::move(cb)). Но, как говорится, содержимое будет перемещено на карту.cb.m_xпосле этого будет пустым. Весь смыслunique_ptrв том, чтобы быть уникальным, то есть не поддающимся копированию, чтобы два экземпляра ссылались на один и тот же управляемый объект.