Здравствуйте, so5team, Вы писали:
M>>MSVC2019, С++17
M>>Есть базовый класс, конструктор копирования запрещён.
S>А что с конструктором перемещения в базовом классе?
S>Ну и как бы не видя базового класса это может превратиться в гадание по кофейной гуще.
Здравствуйте, Marty, Вы писали:
M>>>Есть базовый класс, конструктор копирования запрещён.
S>>А что с конструктором перемещения в базовом классе?
S>>Ну и как бы не видя базового класса это может превратиться в гадание по кофейной гуще.
M>
AD>Тыж явно зовешь конструктор копирования/перемещения через make_shared.
Была надежда, что компилер разберётся
Есть варианты ему подсказать, что там не надо копировать, а перемещать? std::move?
AD>Пусть WindowTimerImpl::create сама возвращает shared.
А других вариантов нет?
В принципе, есть конечно вариант обойтись без create, а всё сделать в конструкторе, но тут есть нюанс — в версии std::make_shared, которая есть в MSVC2019, оно не понимает списка аргументов, чтобы его передать в соответствующий конструктор, так что тут всё равно при вызове std::make_shared либо явно указывать конструктор, либо пытаться передать список инициализации, и надеяться, что там унутре обойдётся без копирования как-нибудь.
Функция create возвращает не указатель а экземпляр обьекта.
бедный make_shared которому это дали пытается найти у класса конструктор которому в качестве параметра надо передать экземпляр самого класса и не может.
Re[2]: Отсутствующий конструктор копирования в MSVC2019 вызывает ош
Здравствуйте, Teolog, Вы писали:
T>Функция create возвращает не указатель а экземпляр обьекта. T>бедный make_shared которому это дали пытается найти у класса конструктор которому в качестве параметра надо передать экземпляр самого класса и не может.
M>В принципе, есть конечно вариант обойтись без create, а всё сделать в конструкторе, но тут есть нюанс — в версии std::make_shared, которая есть в MSVC2019, оно не понимает списка аргументов
Вы точно уверены что список аргументов не подходил? Может конструктор был приватным?
Re[4]: Отсутствующий конструктор копирования в MSVC2019 вызывает ош
M>>В принципе, есть конечно вариант обойтись без create, а всё сделать в конструкторе, но тут есть нюанс — в версии std::make_shared, которая есть в MSVC2019, оно не понимает списка аргументов
T>Вы точно уверены что список аргументов не подходил? Может конструктор был приватным?
С коллегой в четыре глаза смотрели, но, возможно, оба облажались. Щас глянул на прототип make_shared — по идее, работать должно, да. Попробую проверить эту идею
M>Почему он хочет копировать, а не перемещать?
А почему он должен хотеть перемещать?
Чтобы перемещение работало надо кучу условий соблюсти и специально пинать ногами.
Возвращать по значению некопируемый класс — это такое себе
Re[2]: Отсутствующий конструктор копирования в MSVC2019 вызывает ош
AD>Тыж явно зовешь конструктор копирования/перемещения через make_shared.
Боюсь, здесь не так все просто. Ведь create возвращает rvalue, соответственно, shared_ptr конструирует WindowTimerImpl через конструктор перемещения, а не копирования.
Вот дистиллированный пример, который показывает, что если в базовых классах с операторами/конструкторами перемещения все OK, то и с make_shared должно быть OK:
#include <memory>
struct base
{
virtual ~base() = default;
base() = default;
base(const base &) = delete;
base & operator=(const base &) = delete;
base(base &&) = default;
base & operator=(base &&) = default;
};
struct derived : public base
{
int a_;
int b_;
derived(int a, int b) : a_{a}, b_{b} {}
[[nodiscard]] static derived create(int a, int b)
{
return { a, b };
}
};
int main()
{
auto d = std::make_shared<derived>(derived::create(0, 1));
return d->a_ + d->b_;
}
В режиме C++17 нормально компилируется и VS2022, и VS2019.
У меня была когда-то похожая проблема, но там в одном из базовых классов затесался член класса с задизейбленными операторами копирования/перемещения. Поэтому компилятор и для наследника их не мог вывести.
Полагаю, у ТС-а что-то похожее. Но уже в самом WindowTimerImpl.
Re[5]: Отсутствующий конструктор копирования в MSVC2019 вызывает ош
M>С коллегой в четыре глаза смотрели, но, возможно, оба облажались. Щас глянул на прототип make_shared — по идее, работать должно, да. Попробую проверить эту идею
По коду глядя WindowTimerImpl конструктор с тремя параметрами а вызывается с 4. Может в таком-же стиле
Re[4]: Отсутствующий конструктор копирования в MSVC2019 вызывает ош
Здравствуйте, Teolog, Вы писали:
M>>Почему он хочет копировать, а не перемещать? T>А почему он должен хотеть перемещать? T>Чтобы перемещение работало надо кучу условий соблюсти и специально пинать ногами. T>Возвращать по значению некопируемый класс — это такое себе
В общем, да, я облажался, std::make_shared нормально работает со списком параметров конструктора
Здравствуйте, Teolog, Вы писали:
M>>С коллегой в четыре глаза смотрели, но, возможно, оба облажались. Щас глянул на прототип make_shared — по идее, работать должно, да. Попробую проверить эту идею
T>По коду глядя WindowTimerImpl конструктор с тремя параметрами а вызывается с 4. Может в таком-же стиле
Мы с коллегой не в этот раз смотрели. Но, видимо, тогда что-то проглядели, и я в этот раз сразу решил, что проблема существует, и не стал использовать список параметров при вызове make_shared.
Здравствуйте, Marty, Вы писали:
M>Почему он хочет копировать, а не перемещать?
У тебя же перемещение запрещено явно твоим NonCopiable.
Переместить он пытается, но тихо обламывается, потому что всегда можно скопировать если вдруг не прокатило. Далее пытается копировать, но и тут облом. Вот он и говорит, что скопировать не может.
Re: Отсутствующий конструктор копирования в MSVC2019 вызывает ош
Здравствуйте, Marty, Вы писали:
M>Ладно, попробовал вернуть через std::move. Стало ругаться на строчку с ним, но суть осталась та же.
Суть другая. Во время return работает copy elision, copy/move конструкторы не нужны. Обламывается он в момент передачи в make_shared. Как только ты воткнул return std::move, то обламывается уже в момент return.
Разреши мув конструктор, все будет работать.
Re[3]: Отсутствующий конструктор копирования в MSVC2019 вызы
Ну хорошо, а в IObject что? Ты в курсе, что, если ты объявил какой-то конструктор как default, это еще не гарантия того, что этот конструктор будет реально доступен? "default" на раз может реализоваться в "delete", если в классе присутствуют подобъекты(члены, базовые классы, члены базовых классов...) с явно или неявно удаленным конструктором.
Смотри, как получается, ты ждешь, что тебе помогут, не показывая всего кода. Так можно потратить уйму времени с нулевым результатом.
Я бы предложил тебе поработать над минимизированным примером, воспроизводящем проблему, который можно было бы загрузить в какой-нибудь онлайн компилятор. И очень вероятно, что ошибку ты найдешь сам, в процессе работы над этим примером.
--
Справедливость выше закона. А человечность выше справедливости.
Здравствуйте, andrey.desman, Вы писали:
M>>Почему он хочет копировать, а не перемещать?
AD>У тебя же перемещение запрещено явно твоим NonCopiable. AD>Переместить он пытается, но тихо обламывается, потому что всегда можно скопировать если вдруг не прокатило. Далее пытается копировать, но и тут облом. Вот он и говорит, что скопировать не может.
Разве? Я думал, что = default говорит использовать ту версию, которую он сам сгенерил, не?
У меня в NonCopiable copy ctor/op= запрещены
Здравствуйте, andrey.desman, Вы писали:
M>>Ладно, попробовал вернуть через std::move. Стало ругаться на строчку с ним, но суть осталась та же.
AD>Суть другая. Во время return работает copy elision, copy/move конструкторы не нужны. Обламывается он в момент передачи в make_shared. Как только ты воткнул return std::move, то обламывается уже в момент return.
AD>Разреши мув конструктор, все будет работать.
R>Ну хорошо, а в IObject что? Ты в курсе, что, если ты объявил какой-то конструктор как default, это еще не гарантия того, что этот конструктор будет реально доступен? "default" на раз может реализоваться в "delete", если в классе присутствуют подобъекты(члены, базовые классы, члены базовых классов...) с явно или неявно удаленным конструктором.
R>Смотри, как получается, ты ждешь, что тебе помогут, не показывая всего кода. Так можно потратить уйму времени с нулевым результатом.
R>Я бы предложил тебе поработать над минимизированным примером, воспроизводящем проблему, который можно было бы загрузить в какой-нибудь онлайн компилятор. И очень вероятно, что ошибку ты найдешь сам, в процессе работы над этим примером.
Ну, пока решилось, были ошибочные представления о реализации make_shared в MSVC2019, из-за чего я пошел не тем путём
А, вспомнил, почему так получилось. Был код с make_shared, который в MSVC2019 не собирался, а у коллеги в MSVC2022 собирался. Мы поковыряли, и решили, что что-то не так с make_shared в MSVC2019
Здравствуйте, rg45, Вы писали:
M>>Ладно, попробовал вернуть через std::move. Стало ругаться на строчку с ним, но суть осталась та же.
R>Ну у тебя и так здесь rvalue выражение, что ты рассчитываешь получить еще от move?
Я хотел сказать ему: "ну пожалуста-пожалуста, сделай мув"
AD>А,просмотрел, что мув разрешен. Тогда да, что-то не мувается по умолчанию.
Понять бы, что. По всей иерархии наследования никаких полей в классах нет, только чисто виртуальные функции. Ни конструкторов, ни операторов= никакиех нет вообще, только в финальном классе есть конструктор.
А в финальном классе так:
M>Ну, пока решилось, были ошибочные представления о реализации make_shared в MSVC2019, из-за чего я пошел не тем путём
M>А, вспомнил, почему так получилось. Был код с make_shared, который в MSVC2019 не собирался, а у коллеги в MSVC2022 собирался. Мы поковыряли, и решили, что что-то не так с make_shared в MSVC2019
Ну вообще, все, что приходит на вход std::make_shared форвардится в конструкторы объекта создаваемого класса. Конструкторы могут быть разные — копирования, перемещения, преобразования, с одним параметром и с несколькими. Если что-то работает не так, как ожидается, то я стараюсь все такие моменты доводить до полной ясности. Вот когда есть небольшой понятный примерчик, который и там и сям работает, а не работает только на каком-то определенном компиляторе или режиме, вот тогда тогда только можно говорить, что это баг компилятора. А так это просто предположение, а точная причина так и не выяснена пока.
--
Справедливость выше закона. А человечность выше справедливости.
Re[4]: Отсутствующий конструктор копирования в MSVC2019 вызывает ош
Здравствуйте, rg45, Вы писали:
R>Вот когда есть небольшой понятный примерчик, который и там и сям работает, а не работает только на каком-то определенном компиляторе или режиме, вот тогда тогда только можно говорить, что это баг компилятора. А так это просто предположение, а точная причина так и не выяснена пока.
Здравствуйте, Marty, Вы писали:
R>>Вот когда есть небольшой понятный примерчик, который и там и сям работает, а не работает только на каком-то определенном компиляторе или режиме, вот тогда тогда только можно говорить, что это баг компилятора. А так это просто предположение, а точная причина так и не выяснена пока.
M>На MSVC не работает так же, как у меня M>https://godbolt.org/z/ba4Pexz3j
#include <memory>
struct A
{
A() = default;
A(A&&) = default;
A(const A&) = delete;
static A Create() {return {}; }
};
A makeA() { return {}; }
int main()
{
const auto sp = std::make_shared<A>(A::Create());
}
Можешь попробовать компильнуть у себя? Если возникнет та же ошибка — тады ой — это однозначно проблема MSVC. Ну а если откомпилится успешно, тогда твое предположение ошибочно, так получается.
--
Справедливость выше закона. А человечность выше справедливости.
Здравствуйте, Marty, Вы писали:
M>На MSVC не работает так же, как у меня
Потому что ты, негодяй, не сказал, что есть деструктор.
If no user-defined move constructors are provided for a class type, and all of the following is true:
there are no user-declared copy constructors;
there are no user-declared copy assignment operators;
there are no user-declared move assignment operators;
there is no user-declared destructor.
Then the compiler will declare a move constructor as a non-explicit inline public member of its class with the signature T::T(T&&).
Re[8]: Отсутствующий конструктор копирования в MSVC2019 вызы
R>Можешь попробовать компильнуть у себя? Если возникнет та же ошибка — тады ой — это однозначно проблема MSVC. Ну а если откомпилится успешно, тогда твое предположение ошибочно, так получается.
Это собралось. Вопрос в том, что не так у меня в том коде, который не компилируется
Здравствуйте, Marty, Вы писали:
R>>Можешь попробовать компильнуть у себя? Если возникнет та же ошибка — тады ой — это однозначно проблема MSVC. Ну а если откомпилится успешно, тогда твое предположение ошибочно, так получается.
M>Это собралось. Вопрос в том, что не так у меня в том коде, который не компилируется
Во-о-от! И я о том же. Я тебе прямо очень-очень советую пробовать минимизировать твой код. Причина обязательно найдется, уверяю тебя.
--
Справедливость выше закона. А человечность выше справедливости.
Re[9]: Отсутствующий конструктор копирования в MSVC2019 вызы
Здравствуйте, rg45, Вы писали:
M>>Виноват M>>И что делать, если деструктор есть? Кроме как явно описать конструктор/оп= перемещения?
R>Да добавь просто определения-пустышки вместо "default".
Здравствуйте, andrey.desman, Вы писали:
AD>Потому что ты, негодяй, не сказал, что есть деструктор.
AD>
AD>If no user-defined move constructors are provided for a class type, and all of the following is true:
AD> there are no user-declared copy constructors;
AD> there are no user-declared copy assignment operators;
AD> there are no user-declared move assignment operators;
AD> there is no user-declared destructor.
AD>Then the compiler will declare a move constructor as a non-explicit inline public member of its class with the signature T::T(T&&).
[ Note: When the move constructor is not implicitly declared or explicitly supplied, expressions that otherwise would have invoked the move constructor may instead invoke a copy constructor. — end note]
Так что наличие пользовательского деструктора в базовом классе не должно препятствовать генерации конструктора перемещения в производном классе. Конструктор же перемещения базового класса не объявляется удаленным, он просто не генерируется компилятором. При этом конструктор перемещения производного класса может спокойно воспользоваться конструктором копирования базового. Действительно похоже на баг MSVC, причем характерный для отдельной версии.
--
Справедливость выше закона. А человечность выше справедливости.
Re[11]: Отсутствующий конструктор копирования в MSVC2019 вызы
Здравствуйте, rg45, Вы писали:
R>Так что наличие пользовательского деструктора в базовом классе не должно препятствовать генерации конструктора перемещения в производном классе. Конструктор же перемещения базового класса не объявляется удаленным, он просто не генерируется компилятором. При этом конструктор перемещения производного класса может спокойно воспользоваться конструктором копирования базового. Действительно похоже на баг MSVC, причем характерный для отдельной версии.
У меня есть и в финальном классе деструктор.
И не очень понятно, чем наличие деструктора мешает перемещению, он же при этом не должен же использоваться
Здравствуйте, rg45, Вы писали:
R>Да, но там внизу есть еще такая приписочка:
R>
R>[ Note: When the move constructor is not implicitly declared or explicitly supplied, expressions that otherwise would have invoked the move constructor may instead invoke a copy constructor. — end note]
Это то, что у него и происходит — ругается, что не может скопировать.
R>Так что наличие пользовательского деструктора в базовом классе не должно препятствовать генерации конструктора перемещения в производном классе.
Деструктор в производном объявлен.
R>Конструктор же перемещения базового класса не объявляется удаленным, он просто не генерируется компилятором. При этом конструктор перемещения производного класса может спокойно воспользоваться конструктором копирования базового. Действительно похоже на баг MSVC, причем характерный для отдельной версии.
Да, но здесь не оно.
Re[12]: Отсутствующий конструктор копирования в MSVC2019 вызы
Только я сделал в конечном классе, где виртуальный деструктор переопределён
Заработало.
Сделал = default — заработало
R>Если после этого проблема уйдет, то попробуй и конструктор и оператор перемещения просто объявить default.
R>Но это на правах костыля. По идее все должно и так работать. Похоже-таки на баг msvc.
Потом подумал, может ты таки имел в виду самый базовый класс, где один виртуальный деструктор объявлен. Объявил default весь набор. Убрал в финальном классе. Не прокатило.
Здравствуйте, Marty, Вы писали:
M>Виноват M>И что делать, если деструктор есть? Кроме как явно описать конструктор/оп= перемещения?
Явно задекларировать его как default. Но вроде как у тебя все равно же явные телодвижения нужны на перемещение? Timer id переместить в новый объект, в старом занулить, не?
Re[10]: Отсутствующий конструктор копирования в MSVC2019 вызы
Здравствуйте, Marty, Вы писали:
M>И не очень понятно, чем наличие деструктора мешает перемещению, он же при этом не должен же использоваться
Ну, с какой целью генерацию конструктора перемещения поставили в зависимость деструктору, это мне сложно объяснить. Но, с другой стороны, блокировка генерации конструктора не означает запрета семантики перемещения. Должна быть возможность открыть конструктор перемещения, просто объявив его как default. И как показывает практика, на других компиляторах это работает. И даже на msvc, более поздних версий.
--
Справедливость выше закона. А человечность выше справедливости.
Re[10]: Отсутствующий конструктор копирования в MSVC2019 выз
Здравствуйте, andrey.desman, Вы писали: M>>Виноват M>>И что делать, если деструктор есть? Кроме как явно описать конструктор/оп= перемещения? AD>Явно задекларировать его как default.
Так работает, да.
AD>Но вроде как у тебя все равно же явные телодвижения нужны на перемещение? Timer id переместить в новый объект, в старом занулить, не?
Точно, мой косяк
Кстати, а есть рекомендации ведущих собаководов, как правильно писать move ctor/move op=?
Но, по идее, у меня есть значения по умолчанию, или как такая inplace инициализация называется? По идее, mctor = default и наличия такой инициализации должно хватать для генерации того, что мне пришлось ручками натоптать, не?
Здравствуйте, Marty, Вы писали:
M>Потом подумал, может ты таки имел в виду самый базовый класс, где один виртуальный деструктор объявлен. Объявил default весь набор. Убрал в финальном классе. Не прокатило.
Да похоже я просто запутался во фрагментах кода и что-то сказал невпопад.
Ну общий принцип такой — объявляешь деструктор — объяви и конструктор перемещения (возможно, как default).
Но нужно помнить, что объявление конструтора перемещения удаляет копирующие конструктор и присваивание. Именно объявляет как delete, а не просто препятствует их автоматической генерации.
--
Справедливость выше закона. А человечность выше справедливости.
Здравствуйте, Marty, Вы писали:
M>Кстати, а есть рекомендации ведущих собаководов, как правильно писать move ctor/move op=?
Не знаю, как там собаководы, но лично я стараюсь проектировать так, чтоб минимизировать необходимость определять самому специальные функции-члены. Это для меня как один из критериев качества дизайна. При этом необходимо помнить зависимости между ними. Вот хорошая картинка на эту тему:
--
Справедливость выше закона. А человечность выше справедливости.