LINUX.ORG.RU

Хвалёные смарт-поинтеры.

 


0

5

Всем привет!

Сегодня в мире т.н. «modern C++» принято нахваливать смарт-поинтеры. Дескать, это такая крутая технология, которая решает множество проблем. Как это всегда получалось, решение одних проблем порождало решение других проблем. Какие проблемы порождают смарт-поинтеры? Рассмотрим код, который валиден и прекрасно собирается:

struct B {
  virtual B* clone() = 0;
};

struct D : B {
  virtual D* clone() = 0;
};

struct impl : D {
  D* clone() override
  {
    return new impl;
  }
};

int main()
{
  auto b = new impl;
  b->clone();
}

Но стоит только превратить указатели в std::unique_ptr, как всё перестаёт собираться. И вот это уже вызывает смех. Ведь если ув. эксперты, уполномоченные принимать решения в части изменения стандарта, ввели смарт-поинтеры в язык, громогласно заявив при этом, что хватит писать на «голых» указателях, т.к. в современном C++ уже всё на смарт-поинтерах, то почему же тогда с этими хвалёными стандартными смарт-поинтерами ломается ковариантность? :-) C++ как он есть.

А какие вы знаете проблемы со смарт-поинтерами в современном C++?

Ответ на: комментарий от annulen

Используй unique_ptr<B> и будет тебе щастье

Т.е. только в B определить clone()? :-) А потом приводить к D*? :-)

azelipupenko
() автор топика
Ответ на: комментарий от i-rinat

Эта пять!

Нужно срочно писать в комитет, чтобы добавили к C++20

Twissel ★★★★★
()

std::unique_ptr

Это ещё и инструмент управления ресурсами. И он как раз предотвращает клонирование.

invy ★★★★★
()
Ответ на: комментарий от invy

Я так понял, что у автора сего топика всё крайне плохо не только с C++, но и с английским языком. Я бы ему посоветовал реализовывать свои амбиции махая метлой – так он продвинется гораздо больше.

fenris ★★★★★
()
Ответ на: комментарий от invy

Это ещё и инструмент управления ресурсами. И он как раз предотвращает клонирование

Это не так. Ты не понимаешь разницу между владением ресурсом и самим ресурсом? Уникальное владение(в данном случае для освобождения памяти) ортогонально клонированию самого объекта.

И тут было бы удобно иметь ковариантность. Как и для обычных указателей.

anonymous
()
Ответ на: комментарий от fenris

Я так понял, что у автора сего топика всё крайне плохо не только с C++, но и с английским языком.

Как ни странно, но сейчас автор прав. std::unique_ptr обеспечивает уникальное владение и удалит объект после того, как умрет сам.

Умеет ли при этом объект делать свою копию - совершенно неважно.

А ковариантность переход на смарты в данном случае действительно сломает.

anonymous
()

Смотрите какую гадость придумали: револьверы! Все их нахваливают, мол решают много проблем. Но знаете что я вам покажу. Вот валидный кейс: я направляю палку себе на ногу и наживаю на сучек снизу и все ок. А теперь я направляю себе на ногу револьвер и нажимаю на спусковой крючек. Что мы вилим? моя нога прострелена! Ведь ув. эксперты громогласно заявили, что хватит использовать старое оружие. :-) Новые технологии как они есть.

Aswed ★★★★★
()
Ответ на: комментарий от Aswed

А что не так с ковариантностью возвращаемого типа виртуальной функции? Эта же нормальная фича C++. О ней писали и Страуструп и Саттер и Майерс. Где тут выстрел в ногу-то?

А перейти на умный указатель для clone так же неплохое решение, поскольку решаем вопрос с владением объекта.

anonymous
()

Вот это новизна, вот это свежесть мысли. Экспертиза уровня смайлодауна.

В C++ всегда было плохо с ковариантностью и контрвариантностью ( а есть-то вообще где хорошо, кроме как в scala? ). Например указатель на функцию не контрвариантен по аргументам и не ковариантен по возвращаемому значению. А вот в std::function это пофиксили. std::unique_ptr и std::shared_ptr проддерживают ковариантность, кроме как для случая с возвращаемым значением виртульаных функций, но тут ничего не поделать, сам язык надо править, что конечно надо делать с помощью общего решения, а не вбивания костыля для конкретных smart_ptr'ов, а это время, комитет и так загружен на годы вперед.

voivoid
()
Ответ на: комментарий от nezamudich

Кто-нибудь, поясните для тех, кто out of the loop, что тут вообще происходит? Со смарт-поинтерами компилятор не догоняет, что clone() — это один и тот же метод в наследованных классах?

Примерно так. Он не даёт сделать override, т.к. считает что у перекрытой функции другой тип возвращаемого значения.

В C++ работает ковариантность возвращаемых типов для виртуальных функций. Это именно фича. И фича правильная.

С умными указателями же так не получится.

Так что придется или остаться в рамках небезопасного кода или отказаться от ковариантности.

anonymous
()
Ответ на: комментарий от invy

Это ещё и инструмент управления ресурсами.

Это ещё и стандартный класс, который представлен как замена обычным указателям. Шаг вперёд, так сказать. Но, оказывается, нет. Потому что поломали ковариантность, сославшись на «ну это же не в самом языке, а в стандартной библиотеке; вот если бы это новшество было в самом языке, а так мы тут не причём» :-)

И он как раз предотвращает клонирование.

Он предотвращает использование конструктора копирования самого unique_ptr, а не конструктора копирования класса, указанного в качестве его параметра шаблона. Иными словами, походу ты не понимаешь, о чём тут речь :-)

azelipupenko
() автор топика
Ответ на: комментарий от voivoid

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

Ну так и с чем ты спросишь тогда? Автор указал на недостатки в дизайне языка. Вот и все.

Такое ощущение, что его все знают и гнобят заранее, не разобравшись в конкретной теме

anonymous
()
Ответ на: комментарий от Aswed

Новые технологии как они есть.

Верно. Этой мыслью можно было бы озаглавить данную тему. Ведь могли же сделать ковариантность для смарт-поинтеров, но не смогли. Лол :-)

azelipupenko
() автор топика
Ответ на: комментарий от fenris

Я так понял, что у автора сего топика всё крайне плохо не только с C++, но и с английским языком.

А в чём проблемы конкретно? :-)

Я бы ему посоветовал реализовывать свои амбиции махая метлой – так он продвинется гораздо больше.

А ты знаешь, что такое деепричастный оборот? :-) Могу посоветовать сходить в школу, взять пару уроков русского языка, а уж потом давать мне советы :-)

azelipupenko
() автор топика
Ответ на: комментарий от i36_zubov

Во-первых, это не поможет тебе скомпилировать данную программу

Во-вторых, ты стираешь более детальную информацию о типе (это если я правильно понял твою мысль). Т.е. по факту отказываешься от ковариантности.

anonymous
()
Ответ на: комментарий от anonymous

Выстел в ногу тут в том, что технология используется не по назначению. Умные указатели не являются полной эквивалентностью обычных указателей в юзкейсах(не знаю как это слово по русски сказать). Посему уповать на то, что этот кейс перестал работать глупо. В описании unique_ptr черным по белому написано - нельзя размножать указатель. В этом смысл данного класса. Хочешь множить - используй shared_ptr. А ТС такой: «Вот смотите, я пытаюсь сделать то, о что стандартом запрещено и у меня не работает. Неслыханно!»

Aswed ★★★★★
()

как приятно что всегда обсуждается С++ ))) значит он становится все популярнее и востребованнее
иначе бы его уже и не обсуждали

anonymous
()
Ответ на: комментарий от Aswed

Умные указатели не являются полной эквивалентностью обычных указателей в юзкейсах(не знаю как это слово по русски сказать).

Мы это уже поняли :-) Другими словами, умные указатели - это очередной костыль, а не крутая фича «modern C++» :-)

В описании unique_ptr черным по белому написано - нельзя размножать указатель. В этом смысл данного класса. Хочешь множить - используй shared_ptr.

Причём тут «множить»? :-) Лол :-) Скомпиль программу, приведённую в топике :-) Потом замени в ней B* на shared_ptr<B>, D* - на shared_ptr<D> :-) Попробуй собрать - получишь всю ту же ошибку :-) Ты не в теме, но рассуждаешь со своими 5-ю звёздами, эксперт :-)

azelipupenko
() автор топика
Ответ на: комментарий от azelipupenko

очередной РасТист ? синтаксис Раста меняем на с++ и программа не скАмпилится вауууу
меняем везде голые указатели на юник и программа не скАмпилится - вау какой С++ плахой ?)))
чудик сходи мамке цицьку посмокчи, твои потуги выставить С++ только еще больше его укрепляют

anonymous
()
Ответ на: комментарий от anonymous

Разве можно было ждать от тебя что-то другого? :-)

azelipupenko
() автор топика
Ответ на: комментарий от anonymous
user@user:~$ cat test.cpp
#include <memory>
struct B {
  virtual B* clone() = 0;
};

struct D : B {
  virtual D* clone() = 0;
};

struct impl : D {
  D* clone() override
  {
    return new impl;
  }
};

int main()
{
  std::unique_ptr<B> b(new impl);
  b->clone();
}

user@user:~$ gcc test.cpp -lstdc++
user@user:~$ ./a.out
i36_zubov
()
#include <memory>

struct B {
public:
    std::unique_ptr<B> clone() {
        return std::unique_ptr<B>(clone_impl());
    }

private:
    virtual B* clone_impl() = 0;
};

struct D : B {
private:
    virtual D* clone_impl() = 0;
};

struct impl : D {
private:
    D* clone_impl() override
    {
        return new impl;
    }
};

int main()
{
    auto b = new impl;
    b->clone();
}

Смайлодаун сейчас конечно же опять раскудахчется, мол ко-ко-ко-костыли.

voivoid
()
Ответ на: комментарий от voivoid

Смайлодаун сейчас конечно же опять раскудахчется, мол ко-ко-ко-костыли.

Т.е. предлагается скрывать имена функций базовых классов именами функций подклассов, что само по себе уже является действительным прострелом ног :-) Ведь есть даже целый совет от самого Скота Мейерса № 36 - «Никогда не переопределяйте наследуемые невиртуальные функции» из его знаменитой книги «Эффективное использование C++»? :-) Или этот совет уже deprecated? :-) Или ты даже Мейерса не читал? :-) Или позабыл давно Мейерса? :-) Лол :-)

azelipupenko
() автор топика
Ответ на: комментарий от voivoid

Наверное, лучше тогда вот так:

struct B {
  virtual B * clone_raw() = 0;

  static template<typename T> unique_ptr<T> clone(T & what) {
    static_assert(std::is_base_of_v<B, T>, "T should be derived from B");
    return {what.clone_raw()}
  }
};
struct D : public B {
  D * clone_raw() override { return new D{*this}; }
  ...
};
struct C : public B {
  C * clone_raw() override { return new C{*this}; }
  ...
};
...
int main() {
  auto c1 = std::make_unique<C>(...);
  auto c2 = B::clone(*c1);
  ...
}
Костыльно, но вроде как должно работать.

ЗЫ. Код не проверял.

eao197 ★★★★★
()
Ответ на: комментарий от azelipupenko

Другими словами, умные указатели - это очередной костыль

«Никогда не было и вот опять»
С++ целиком состоит из костылей. Не нравится не пользуйся. Пользуешься - читай инструкцию.

но рассуждаешь со своими 5-ю звёздами

Завидуешь что-ли?

Aswed ★★★★★
()
Ответ на: комментарий от azelipupenko

Т.е. предлагается скрывать имена функций базовых классов именами функций подклассов, что само по себе уже является действительным прострелом ног :-) Ведь есть даже целый совет от самого Скота Мейерса № 36

Едрить ты бестолочь ( ну или жирный тролль ). Мною приведенный код это пример паттерна шаблонный метод. А совет Мейерса вообще не о том, а о сокрытии одноименных невиртуальных методов.

voivoid
()
Ответ на: комментарий от voivoid

Едрить ты бестолочь ( ну или жирный тролль ). Мною приведенный код это пример паттерна шаблонный метод. А совет Мейерса вообще не о том, а о сокрытии одноименных невиртуальных методов.

Бестолочь - это ты. Без переопределения clone() твоя натужная попытка не стоит ничего.

azelipupenko
() автор топика
Ответ на: комментарий от anonymous

некоторые с ICQ=55.

Пятидесятипятилетние асечники

Deleted
()
Ответ на: комментарий от azelipupenko

Так-так-так, что тут у нас? Смайлодаун сломался и смайлики больше не постит?

Бестолочь - это ты. Без переопределения clone() твоя натужная попытка не стоит ничего.

Лолшто? clone_impl - приватная виртуальная функция, переопределяется в каждом классе иерархии. clone() определена только в базовом классе, далее не переопределяется. Это всем известный паттерн - шаблонный метод. Еще известный так же как NVI ( non-virtual interface ). Кстати раз уж так любишь Скотта Мейерса, может посмотреть что он про NVI пишет - https://books.google.ru/books?id=Qx5oyB49poYC&pg=PA177&lpg=PA177&...

voivoid
()
Ответ на: комментарий от voivoid

Еще известный так же как NVI ( non-virtual interface ).

NVI не поможет сломанной смарт-поинтерами ковариантности.

azelipupenko
() автор топика
Ответ на: комментарий от eao197

Костыльно, но вроде как должно работать.

Браво. Теперь остаётся отправить «банде 4-х» заявку на добавление нового паттерна. Предлагаю назвать его «костыльный клон».

azelipupenko
() автор топика

Как это всегда получалось, решение одних проблем порождало решение других проблем

Страустрап и сам уже замечал что считает C++ неудачным..

смиритесь: те кто понял что C++ неудачен - раньше вас написали другие языки.

anonymous
()
Ответ на: комментарий от voivoid

Лолшто? clone_impl - приватная виртуальная функция, переопределяется в каждом классе иерархии.

Лол :-) С таким же успехом можно было бы сделать clone() виртуальным, и никаких clone_impl() не нужно:

struct B {
  virtual std::unique_ptr<B> clone() = 0;
};

struct D : B {};

struct impl : D {
  std::unique_ptr<B> clone() override
  {
    return std::make_unique<impl>();
  }
};

По-видимому, ты прочитал в чьём-то бложике костыльное решение проблемы топика, но даже воспроизвести его толком не смог :-)

azelipupenko
() автор топика
Ответ на: комментарий от azelipupenko

Вы еще доколупайтесь к тому, что так не работает:

#include <vector>

class A {};
class B : public A {};

int main() {
    B b1, b2, b3;
    std::vector<B*> b{ &b1, &b2, &b3 };
    std::vector<A*> a = b; // Oops!
}
а вот так работает:
#include <vector>

class A {};
class B : public A {};

int main() {
    B b1, b2, b3;
    std::vector<B*> b{ &b1, &b2, &b3 };
    std::vector<A*> a{b.begin(), b.end()};
}
И, главное, смайликов, смайликов побольше.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

Вы еще доколупайтесь к тому, что так не работает:

Ну да :-) Это же C++ :-)

И, главное, смайликов, смайликов побольше.

А это уже Лисп :-)

azelipupenko
() автор топика
Ответ на: комментарий от azelipupenko

Это же C++ :-)

Не хватает мозгов для безопасного использования C++? Возьмите Rust, там такой проблемы нет в принципе.

А это уже Лисп :-)

Вы не можете заработать себе на жизнь Лиспом. Приходится перебиваться С++. Но на C++ мозгов не хватает. Поэтому см. выше.

Смайлодаун остается дауном даже став регистрантом.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

Не хватает мозгов для безопасного использования C++? Возьмите Rust, там такой проблемы нет в принципе.

Не хватает мозгов понять о чём тема? Причём тут «безопасное использование C++»? Я бы и рад безопасно его использовать, но смарт-поинтеры в C++ не умеют в ковариантность, если их использовать в качестве возвращаемого значения виртуальных функций.

Возьмите Rust, там такой проблемы нет в принципе.

Да?

Вы не можете заработать себе на жизнь Лиспом. Приходится перебиваться С++.

А тебе то откуда знать? :-) Может быть, это ты перебиваешься C++, потому что ничего другого не умеешь? :-)

Но на C++ мозгов не хватает. Поэтому см. выше.

Как раз таки хватает. Иначе бы не было данного топика. Лол :-)

azelipupenko
() автор топика
Ответ на: комментарий от azelipupenko

Не хватает мозгов понять о чём тема?

Тема о древнем баяне, до которого смайлодаун только-только дорос. Ее обсосали еще во времена std::auto_ptr.

Причём тут «безопасное использование C++»?

При том.

Я бы и рад безопасно его использовать, но смарт-поинтеры в C++ не умеют в ковариантность, если их использовать в качестве возвращаемого значения виртуальных функций.

Массивы в C++ так же не умеют в ковариантность. И в контравариатность в C++ как-то не очень. Только те, кто хотят говорить по сути, обсуждают способы сохранения ног, а не пытаются уныло троллить.

Да?

Да, но можете и сами проверить.

А тебе то откуда знать?

Зарабатывали бы вы Лиспом, у вас бы не было ни времени, ни необходимости троллить C++ на LOR-е.

Может быть, это ты перебиваешься C++, потому что ничего другого не умеешь?

Настолько же хорошо, как C++, на данный момент не умею. Что сказать-то хотели?

Как раз таки хватает. Иначе бы не было данного топика.

Об отсутствии мозгов говорит уже стиль общения с обилием смайликов. А данный топик является лишним тому доказательством.

eao197 ★★★★★
()
Ответ на: комментарий от i36_zubov

И что ты показал по-твоему? C++ поддерживает ковариантность возвращаемого типа для виртуальных методов. Для обычных указателей работает, для умных - нет. Система типов не позволяет.

anonymous
()
Ответ на: комментарий от voivoid

Не костыли. Но информацию о типе ты потеряешь при использовании клиентом. Этот код бесполезен.

anonymous
()
Ответ на: комментарий от eao197

Тема о древнем баяне, до которого смайлодаун только-только дорос. Ее обсосали еще во времена std::auto_ptr.

Обсосать, обсосали, но так ничего и не решили. Поговорили и разошлись.

При том.

При чём?

Массивы в C++ так же не умеют в ковариантность. И в контравариатность в C++ как-то не очень. Только те, кто хотят говорить по сути, обсуждают способы сохранения ног, а не пытаются уныло троллить.

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

Зарабатывали бы вы Лиспом, у вас бы не было ни времени, ни необходимости троллить C++ на LOR-е.

Но у меня есть время, как и у тебя.

Настолько же хорошо, как C++, на данный момент не умею. Что сказать-то хотели?

А что ты сказать хотел?

Об отсутствии мозгов говорит уже стиль общения с обилием смайликов. А данный топик является лишним тому доказательством.

Данный топик о проблеме C++.

azelipupenko
() автор топика
Ответ на: комментарий от eao197

Должно работать, да. Но ты же согласен, что система типов в C++ не позволяет выразить ковариантность для смартпоинтеров? Так с чем споришь?

anonymous
()
Ответ на: комментарий от azelipupenko

но так ничего и не решили

И тут появляется смайлодаун, весь такой в лолах и смайлах, и проблему решает.

Или нет?

При чём?

При том. См. про отсутствие мозгов.

При этом, как только проблема поднимается, приспособленцы начинают рычать, что их потревожили в их болоте.

Если бы проблема поднималась с предложением ее решить. Так ведь здесь же тупой троллинг уровня смаулодауна.

Для совсем тупых: проблема старая и давно известная. С ней редко сталкиваются. А когда сталкиваются, то спокойно решают обходными путями. Устраивать цирк из очередного косяка в C++ может только такая альтернативно одаренная личность, как смайлодаун.

Но у меня есть время, как и у тебя.

Очередное подтверждение, что любимый вами Лисп не может вас прокормить.

А что ты сказать хотел?

То, что у меня нет проблем с тем, что я знаю инструмент, которым пользуюсь, и не знаю того, с чем дел не имею.

eao197 ★★★★★
()
Ответ на: комментарий от anonymous

Но ты же согласен, что система типов в C++ не позволяет выразить ковариантность для смартпоинтеров?

Этой новости уже лет 20, минимум.

Так с чем споришь?

А я с чем-то спорю?

eao197 ★★★★★
()
Ответ на: комментарий от azelipupenko

Данный топик о проблеме C++.

будьте предельно точны, о вашей проблеме с С++
у других проблем с С++ нет, как и в данном вопросе

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.