All streams
Search
Write a publication
Pull to refresh
82
0.1
Евгений Охотников @eao197

Велосипедостроитель, программист-камикадзе

Send message

Демонстрация "как в этом вашем C++ отстрелить себе ногу не прилагая никаких усилий" получилась наотлично.

Я хз что такое MR, но на слабо вы решили взять не того. В последние годы часть моей работы состоит как раз в том, чтобы бить по рукам за говнокод с ручными new/delete, возвратом std::string-ов по значению и т.п.

Если бы вы свой Canvas определили хотя бы так:

using ShapeUptr = std::unique_ptr<Shape>;
class Canvas {
    std::vector<ShapeUptr> shapes;
public:
    void add(ShapeUptr s) { shapes.push_back(std::move(s)); }
    void render() const {
        for (auto & s : shapes) s->draw();
    }
};

То у вас бы получилось и короче, и надежнее.

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

https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#r3-a-raw-pointer-a-t-is-non-owning
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#r11-avoid-calling-new-and-delete-explicitly
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#r20-use-unique_ptr-or-shared_ptr-to-represent-ownership

Как же печально видеть в 2025-ом году C++ный код с ручными new/delete и детскими ошибками, описанными еще в первых изданиях "Язык программирования C++" :(((

Предлагаю читать

Предлагаю подумать о том, что если вопрос вам был задан, значит ваши слова не были поняты. А раз не были поняты, то их повторение ситуацию не прояснит.

Спасут вас от копирования огромного вектора и от ошибки компиляции при попытке скопировать объекты некопируемых классов. Ваш Кэп.

Во-первых, каким образом?

Во-вторых, как это все относится к обсуждению якобы опасной реализации bind_first?

Я вас просил изменить пример на использование std::cref. Сможете?

Предлагаю использовать инструменты по требованию задачи. Не нужен shared_ptr — не используйте, пистолет у виска никто не держит.

Напомню, что речь про реализацию bind_first. Текущая реализация позволяет вообще избежать копирования или использования каких-то дополнительных сущностей вроде std::shared_ptr.

Про shared_ptr заговорили вы. Значит вы (а не я) видите в этом смысл.

Так ref/cref это не про владение

Тогда к чему это?

это к вашему последнему примеру про копирование большого вектора и мьютекса и кондишн вара, которые не копируемые.

Как здесь помогут std::ref/cref?

Нужно передать владение — мувайте, нужно расшарить — шарьте теми же shared_ptr'ами.

Т.е. вы предлагаете всегда использовать shared_ptr даже когда немувабельный объект создать на стеке (или внутри другого объекта) и гарантировать его доступность другими средствами?

пока не наблюдал ни субд ни редакторов.

У меня знакомый работает в Picodata. Не знаю, на чем у них сама Picodata сделана, а вот Radix (замена Redis-а) у них пишется на Rust.

Ну и как по мне, если условный PostgreSQL умудряются тянуть на чистом Си, то уж на Rust-е его аналог было бы делать и сподручнее, и безопаснее.

Субд или редактор на Расте я тоже себе плохо представляю.

Зря. Rust более чем годный язык для таких задач.

В gcc относительно недавно (что то раньше, что то позже) добавлены Ada, D, Modula-2.

D не взлетел, плюс он с GC, а без GC D нужен еще меньше, чем D с GC. Как бы это не было неприятно любителям D, но у D все еще хуже, чем у Haskell-я.

Modula-2 давно не актуальна за исключением чего-то совсем экзотического с точки зрения массового производства. Т.е. разработка бортового ПО для ракет на Modula-2 -- вполне возможно. Делать сейчас на Modula-2 какую-то СУБД или альтернативу MS Word... Вы серьезно?

Ada. Получше, чем у Modula-2. Но если брать всю экосистему с доступными библиотеками, книгами, статьями и пр., количества программистов знающих или хотя бы интересующихся, то вряд ли она может конкурировать с Rust и C++. Так что как язык для разработки софта -- вполне себе ОК, но как инструмент для написания тех же СУБД или редактора документов -- вряд ли.

А если допустим GC

То это будет совсем другая история и совсем другой выбор.

Но в любом случае, возвращаясь к топику, Rust мне не продашь.

Rust учитывает ошибки C++ и это пока что единственная реальная альтернатива C++ в тех нишах, где C++ пока еще нужен (нативный код, отсутствие сборщика мусора, контроль за происходящим, дешевая интеграция с ОС или даже работа без ОС).

За пределами этого (имхо) сужающегося сегмента нет смысла выбирать Rust или C++.

Но это стандартом для всех систем и оптимизаторов! не гарантируется.

За стандарт не буду говорить, не знаток.

Получить приключения со строковыми литералами можно и на x86/x64 при ручной загрузке/выгрузке DLL/so. Но C++ здесь обвинять можно только от обиды на весь свет.

А теперь немного поменяем вызов

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

Простой аналог из стандартной библиотеки C++ -- это std::min. Запросто может приводить к повисшим ссылкам.

std::ref/cref.

Чуть менее чем бесполезны для защиты от протухших ссылок. Но дело даже не в этом.

Возьмем сильно сокращенный пример:

#include <iostream>
#include <string>

using namespace std::string_literals;

template<typename Str, typename Arg>
struct Worker {
    void operator()(const Str & s, Arg i) {
        std::cout << s << " " << i << std::endl;
    }
};

template <template <typename...> typename F, typename... FST>
auto
bind_first(FST &&... fst) {
	return [&]<typename... LST>(LST &&... lst) {
		F<FST..., LST...>{}(std::forward<FST>(fst)..., std::forward<LST>(lst)...);
	};
}

int main()
{
    const auto s = "Some rather long string to avoid small object optimization, "s;
    auto worker = [&s]() {
        return bind_first<Worker>(s);
    }();
    worker(0);
}

https://godbolt.org/z/bbP8fh5hP

Если перенести s внутрь лямбды, порождающей worker, т.е.:

int main()
{
    auto worker = []() {
        const auto s = "Some rather long string to avoid small object optimization, "s;
        return bind_first<Worker>(s);
    }();
    worker(0);
}

то мы ожидаемо получим проблемы, о которых вы говорите.

Но вопрос в другом: как вы не меняя Worker-а вставите std::cref в вызов bind_first, чтобы ничего не поломалось?

Вот так не получится:

bind_first<Worker>(std::cref(s));

И да, в вашем примере (если бы он был рабочим), это была бы строковая переменная.

Во-первых, пример не мой.

Во-вторых, если мы говорим о C++, то в C++ вообще нет такого понятия, как "строковая" переменная.

В-третьих, в месте вызова bind_first, а именно:

auto const sendOrderGoog{bind_first<SendOrder>("Goog")};

нет строки, есть строковый литерал типа const char[5], время жизни которого равно времени жизни всей программы. Внутрь bind_first он приходит, полагаю, как что-то вроде const char (&)[5] (лень проверять как это реально должно записываться). Т.е. создаваемая в bind_first лямбда захватывает ссылку, которая не может протухнуть.

Так что прошу еще раз показать где в приведенном коде есть возврат ссылки на локальную переменную. Ведь вы ее видите, ну так покажите.

Что касается списков захватов у лямбды, т.е. разницы между [=] и [&], то тут можно сказать следующее:

  • очень плохо, когда пишут [&] бездумно. Это прямой путь к проблемам;

  • время от времени приходится писать [&] ради эффективности (чтобы избежать копирования тяжелых объектов), либо когда мы имеем дело с некопируемыми в принципе объектами.

Так что на первый взгляд обсуждаемая bind_first выглядит потенциально опасной, но зато она позволит избежать проблем, например, в таком случае:

std::vector<std::uint8_t> raw_data(100uz * 1024uz * 1024uz, 0);
std::mutex data_lock;
std::condition_variable data_ready_cv;

auto worker = bind_first<some_worker>(raw_data, data_lock, data_ready_cv);

Поскольку сейчас можно и молодежно поливать C++ известной субстанцией, то самое время для "фу, небезопасно, можно отстрелить себе ногу".

В корутине локальная переменная (аргумент функции bind_first) захватывается по ссылке

Где вот здесь:

	auto const sendOrderGoog{bind_first<SendOrder>("Goog")};

есть локальная переменная? Под оной понимается указатель на строковый литерал?

Просто тупые сишники не знают, что нельзя возвращать ссылку на локальную переменную

А где здесь возврат ссылки на локальную переменную?

Намек на то, что в bind_first аргументы fst внутри лямбды захватываются по ссылке?

Так обсёр-то в чём?

В том, что вы сожалеете о годах, потраченных на C++. Более того, все еще хуже, если здесь вы говорите правду:

сожалею как раз о том, что потратил некоторую часть этой молодости на высшее образование, математику, и прочее

Вам кажется, что где-то в жизни вы сильно ошиблись, и поэтому теперь бегаете по статьям о C++ чтобы всем рассказать, насколько C++ плох. Что очень похоже, что вы сами обгадились, а теперь носитесь с полными шароварами и кричите, что виноват C++.

Так вот, C++ никак не может быть виноват на то, что сейчас вам кажется, что какую-то часть жизни вы прожили не так.

Когда же вы бегаете по Хабру и высказываетесь в духе:

"чтобы потом было весело делать головоломки и отсеивать людей на интервью». Хорошо разве что для job security."

"Как предмет для шуток, разве что."

"«Практичные шаблоны C++» (особенно формата и качества реализации а-ля 90-ые) — вы тут на стендап-комика тренируетесь, что ли?"

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

Потому что там обсуждение конкретных технических вопросов.

А выяснение причин, почему одна технология стала гораздо более востребованной, чем другая, выходит за рамки конкретных технических вопросов. Вам от этого, наверное, неуютно, раз вы попытались унизить меня дав оценку тому, что я делаю.

Только и здесь вы продемонстрировали свою альтернативную одаренность: вы отрицаете аргументацию вида "раз популярно, значит хорошо", но зачем-то приплетаете "никому не нужной местечковой". Видимо, аргументы о популярности внезапно начинают работать когда это вам удобно.

А вот «полиморфизм а-ля темплейты C++ — хорошее решение потому, что C++ популярный» — это манямирок, притягивание решения к желаемому ответу, и так далее.

А теперь внимание, вопрос №1: где я говорил, что полиморфизм в C++ -- это "хорошее решение"? Цитату, пожалуйста.

Практичность и состоятельность были, а вот "плохо", "хорошо", "отлично", "прямо" или "криво" -- вот это найдите в моих словах.

Перл, например, вполне себе оказался практичным и состоятельным. Как и Java. Что не мешает мне отзываться об этих языках в негативном ключе.

Что не разделяю вашего восторга по поводу некоторой технологии

Внимание, вопрос №2: где я высказывал хоть какие-то восторги по поводу сделанного в C++? Цитату, пожалуйста.

Получается так: вы говорите про "максимально криво", я прошу всего лишь две вещи:

a) сказать, где же было "максимально прямо". И, вполне ожидаемо, мне приводят в пример то, что востребовано долями процентов от общего числа разработчиков ПО. Да и среди тех, у кого востребовано, изрядная доля не программистов, а ученых из области computer science (т.е. не имеющих отношения к промышленной разработке софта);

b) объяснить почему эти самые конкуренты, у которых "максимально прямо", не смогли получить такого же широкого распространения, как C++. И ответа на этот вопрос нет вообще. А если кто-то всерьез думает, что причина в "непохожи на Алгол", то у меня для них плохие новости.

Ваши высказывания похожи на "У "Ласкового мая" максимально примитивная плохая музыка, тогда как у Дебюсси..." Только вот если нужно собирать стадионы, то с "Ласковым маем" это возможно, а вот с Дебюсси -- большой вопрос. И проблема в том, что в оценку творчества "Ласкового мая" кроме "максимально примитивный" (что так и есть) начинают добавлять еще и "плохой".

Так же и по поводу C++: из того, что в C++ что-то делано примитивно и не так, как в Haskell, не следует то, что это "плохо", "криво" (или еще какой-то уничижительный эпитет).

И вот вместо того, чтобы задуматься о том, почему же в реальном мире распространение получают отнюдь не самые "максимально прямые" инструменты (C++ и только что упомянутый Perl тому примеру) вы начинаете видеть в моих словах "полиморфизм а-ля темплейты C++ — хорошее решение" и "вашего восторга по поводу некоторой технологии", после чего спорите с тем, чего я не говорил.

Отсюда и вытекает, что в вашем случае аргументы ad hominem более уместны, чем попытки объяснить чем реальный мир отличается от вашего манямирка.

Вы снова повторяете свой псевдоаргумент о том, что если язык, имеющий нравящуюся вам фичу, популярен, то это говорит о (если вообще не «благодаря») качестве этой фичи.

Это реальность, которая вам не нравится и от которой вы бежите в свой манямирок.

Инструменты, вроде C++ или Python-а (да и Haskell-я, если я правильно помню историю его появления) создаются не для академических исследований, а для практического использования. Создаются, выпускаются в мир и дальше выживают те, кто практичнее (+ некоторое стечение обстоятельств).

C++ и Python выжили. Более того, они заняли значительную долю своей ниши. Haskell и Ruby где-то выживают.

«Практичные шаблоны C++» (особенно формата и качества реализации а-ля 90-ые) — вы тут на стендап-комика тренируетесь, что ли?

Если вы обосрались с C++ и теперь горько жалеете о бесцельно прожитых годах, то это ваши проблемы, которые про качества C++ не говорят ровным счетом ничего.

Я написал кучу кода на шаблонах, начиная с той самой середины 1990-х. Что-то из мной написанного используется совершенно разными людьми в совершенно разных проектах. Так что я-то знаю о чем говорю.

Более того, если бы в C++ не было шаблонов, то с большой долей вероятности я бы давно использовал что-то другое.

А тот факт, что вы анонимный никто, тогда как я здесь под своим реальным именем и любой может посмотреть, что и как я делаю, ставит нас в неравные условия: вы можете себе позволить попытаться унизить меня выражениями вроде "никому не нужной местечковой библиотеки" просто потому, что никто не может оценить то, что делаете вы. Ибо вы никто и звать вас никак.

Есть вы, влезающий в этот разговор с псевдоаргументом про популярность.

Вы опять ничего не поняли.

Популярность -- это только следствие того, что сделанное в C++ оказалось лучше, чем вы об этом думаете. Шаблоны в C++ оказались практичными, что и стало ключом к их широкому применению. И конкурентов у него тогда не было, даже если брать в расчет Ada.

Получилось, что C++ стал первым по настоящему большим полигоном, на котором этот самый параметрический полиморфизм массово испытывался.

То, что там не все хорошо -- это уже другая сторона медали.

Вы же ничего этого в упор не видите, поэтому вам кажется, что я меняю тему разговора.

Я бы, конечно, мог сказать, что автор никому не нужной местечковой библиотеки

При общении с вами есть еще и такая проблема, что вы никто и звать вас никак.

он в ответ кроет последним универсальным аргументом: «зато популярно!»

И что вы можете с этим поделать? В очередной раз рассказать, что все в Haskell-е все сделано "максимально прямо"?

Мир такой, какой он есть. Если вы сожалеете о впустую потраченной на C++ молодости, то это не значит, что все должны переживать о том, насколько C++ плох и бежать искать что-то лучше.

Information

Rating
3,774-th
Location
Гомель, Гомельская обл., Беларусь
Registered
Activity