LINUX.ORG.RU

юнионы в C++

 


2

4

Пишу телегу против плюсов. В связи с этим вопрос - насколько широко в плюсах используются нуль-терминированные строки, юнионы, неумные указатели и всё такое плохое, что делает Си опасным языком.

Даже интересует не столько то, насколько они используются в существующих программах, а есть ли примеры программ, где хорошие средства плюсов сконсолидировались и поставили заслон от опасных конструкций Си, позволив полностью избежать их использования и избавиться от типичных ошибок Си. Можно ли так написать что-то существенно сложное? Сделано ли это в любимых библиотеках (Буст, QT и иже с ними)? Вторая часть вопроса - это неопределённое поведение. В Си его много. Это подаётся как фича, но с точки зрения безопасности это дыра. Меньше ли неопределённого поведения в С++?

Есть две полярные точки зрения на вопрос:

а) С++ перекрывает Си, поэтому там всё сделано по-другому, поэтому безопасность выше б) С++ - наследник Си и в целом наследует его недостатки.

Поскольку я мало пишу на Си и ещё меньше на Си++, у меня нет сложившегося мнения на эту тему. А у ЛОРа наверняка есть мнение, даже несколько.

★★★★★

Последнее исправление: xaizek (всего исправлений: 4)

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

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

Если такая простая структура вызывает у вас желание встать раком, то вам лучше сменить язык программирования. А лучше и профессию.

Когда там уже лайки на лоре?

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

Хорошо, найдите мне реализацию Deflate на C++, чтобы она была вся разбита на маленькие функции. Я с ходу нашёл этот код по ссылке, но там есть build_decode_table (на 215 строк) и другие функции примерно на 100 строк.

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

static const uint32_t literal_length_values[max_literal_length_codewords] = { literal(0), literal(1), literal(2), literal(3), literal(4), literal(5), literal(6), literal(7), literal(8), literal(9), literal(10), literal(11), literal(12), literal(13), literal(14), literal(15), literal(16), literal(17), literal(18), literal(19), literal(20), literal(21), literal(22), literal(23), literal(24), literal(25), literal(26), literal(27), literal(28), literal(29), literal(30), literal(31), literal(32), literal(33), literal(34), literal(35), literal(36), literal(37), literal(38), literal(39), literal(40), literal(41), literal(42), literal(43), literal(44), literal(45), literal(46), literal(47), literal(48), literal(49), literal(50), literal(51), literal(52), literal(53), literal(54), literal(55), literal(56), literal(57), literal(58), literal(59), literal(60), literal(61), literal(62), literal(63), literal(64), literal(65), literal(66), literal(67), literal(68), literal(69), literal(70), literal(71), literal(72), literal(73), literal(74), literal(75), literal(76), literal(77), literal(78), literal(79), literal(80), literal(81), literal(82), literal(83), literal(84), literal(85), literal(86), literal(87), literal(88), literal(89), literal(90), literal(91), literal(92), literal(93), literal(94), literal(95), literal(96), literal(97), literal(98), literal(99), literal(100), literal(101), literal(102), literal(103), literal(104), literal(105), literal(106), literal(107), literal(108), literal(109), literal(110), literal(111), literal(112), literal(113), literal(114), literal(115), literal(116), literal(117), literal(118), literal(119), literal(120), literal(121), literal(122), literal(123), literal(124), literal(125), literal(126), literal(127), literal(128), literal(129), literal(130), literal(131), literal(132), literal(133), literal(134), literal(135), literal(136), literal(137), literal(138), literal(139), literal(140), literal(141), literal(142), literal(143), literal(144), literal(145), literal(146), literal(147), literal(148), literal(149), literal(150), literal(151), literal(152), literal(153), literal(154), literal(155), literal(156), literal(157), literal(158), literal(159), literal(160), literal(161), literal(162), literal(163), literal(164), literal(165), literal(166), literal(167), literal(168), literal(169), literal(170), literal(171), literal(172), literal(173), literal(174), literal(175), literal(176), literal(177), literal(178), literal(179), literal(180), literal(181), literal(182), literal(183), literal(184), literal(185), literal(186), literal(187), literal(188), literal(189), literal(190), literal(191), literal(192), literal(193), literal(194), literal(195), literal(196), literal(197), literal(198), literal(199), literal(200), literal(201), literal(202), literal(203), literal(204), literal(205), literal(206), literal(207), literal(208), literal(209), literal(210), literal(211), literal(212), literal(213), literal(214), literal(215), literal(216), literal(217), literal(218), literal(219), literal(220), literal(221), literal(222), literal(223), literal(224), literal(225), literal(226), literal(227), literal(228), literal(229), literal(230), literal(231), literal(232), literal(233), literal(234), literal(235), literal(236), literal(237), literal(238), literal(239), literal(240), literal(241), literal(242), literal(243), literal(244), literal(245), literal(246), literal(247), literal(248), literal(249), literal(250), literal(251), literal(252), literal(253), literal(254), literal(255),

Дальше читать уже не хочется, если честно

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

Тут дело в том, что мы в своей работе опираемся на абстракции, которые построены на других абстракциях.

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

byko3y своими вопросами и утверждениями (возможно, глупыми) даёт Вам это сделать в увлекательной форме.

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

Я считаю нужным вмешиваться потому, что персонажи типа byko3y или den73 своим бредом срут в головы менее опытным коллегам. А это не есть хорошо.

И ничего увлекательного в том, что приходится на пальцах разъяснять заблуждения byko3y нет.

Но из этого не следует, что всегда есть альтернатива.

Практика показывает, что это зависит от опыта того, кто смотрит на код.

Возьмите какой-нибудь нетривиальный алгоритм сортировки или архивации.

Вообще-то я думал написать несколько слов про пример с case на 100 типов сообщений коммуникационного протокола.

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

Я так и не увидел доводов, которые бы позволили считать Страуструпа «манагером-продажником». Какой-то бред на заданную тему был, доводов не было

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

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

Да тут далеко и ходить не нужно.

Сразу же: https://github.com/mylioja/deflate_decompressor/blob/main/deflate_decompressor.cpp#L194-L200 – кандидат на вынесение в мелкую вспомогательную функцию. Даже не так. На отдельный тип с конструктором, вроде такого:

struct length_counts_holder {
  int length_counts_[max_possible_codeword_length + 1];

  length_counts_holder(
    const uint8_t * codeword_length,
    const int number_of_symbols)
  {
    std::memset(length_counts_, 0, sizeof length_counts_);
    for (int symbol = 0; symbol < number_of_symbols; symbol++)
    {
      length_counts_[codeword_lengths[symbol]]++;
    }
  }
};

Буквально следом: https://github.com/mylioja/deflate_decompressor/blob/main/deflate_decompressor.cpp#L202-L215 – туда же.

Аналогично следом: https://github.com/mylioja/deflate_decompressor/blob/main/deflate_decompressor.cpp#L217-L249 – так же напрашивается на отдельную функцию.

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

ты сам продаешь свои способности создавать и разбираться в зубодробильных конструкциях?

Способности решать сложные задачи и создавать удобные инструменты

А «выбирать удобные инструменты» в этой школе не учат?

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

Да, я предпочитаю писать софт, а не разбираться с инструментом. Как я уже писал, я отработал 2 года на JS, и я так и не узнал, как работает приведение типов в этом языке. Более того, я не вижу ни одной причины ни мне, ни какому-то другому программисту это узнавать. В любых подобных языках с богатым прошлым о половине фич нужно знать только для того, что избегать их и не давать ими пользоваться членам твоей команды. Половина фич C++ поломаны by-design — это реальность. Deal with it.

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

Дальше читать уже не хочется, если честно

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

Лично я бы не стал делать массив константным и заполнил его парой циклов. Но я ленив. Или byko3y убедил Вас, что const - зло?

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

Вообще-то я думал написать несколько слов про пример с case на 100 типов сообщений коммуникационного протокола.

Я только за. Пишите.

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

В протоколе есть 100 команд. Для обработки их можно использовать case, благодаря которому мы и получим большое количество строк кода. Как можно декомпозировать? Ну можно сделать map с указателями на функции. Но это не будет сильно лучше по читаемости, да ещё и внесёт задержки.

Я бы лично шел по такому пути:

  • сперва бы вынес обработку каждой команды протокола в отдельную функцию/метод;

  • диспетчеризацию бы этих функций написал бы сперва максимально простым способом. Скорее всего, через switch/case. Т.е. что-то вроде:

void handle_pdu(const pdu_id_t & id, const pdu_data_t & data)
{
  switch(id)
  {
    case pdu_id::first_pdu_id: return handle_first_pdu(data);
    case pdu_id::second_pdu_id: return handle_second_pdu(data);
    ...
  }
}

Даже скорее всего бы применил какой-нибудь макрос для того, чтобы все это выглядело бы более декларативно.

Возможно, использовал бы std::map, но тут особых преимуществ сходу не видно, т.к. основной объем кода все равно будет составлять инициализация этого std::map.

Т.е. сперва бы сделал самый простой работающий вариант.

А уже затем, если бы его скорость не устраивала бы, то тогда бы уже начинал что-то менять. Но лишь после того, как увидел бы где и что подтормаживает.

И уж точно не стал бы начинать с того, чтобы код по обработке конкретного PDU писать прямо в switch-е по диспетчеризации.

Да, функция handle_pdu могла бы вырасти до 120-150 строк. Но если бы там был исключительно декларативный код, который бы просто явным образом перечислял обрабатываемые случаи, то это вполне себе норм. Тут уже тупо нет места для какой-то дальнейшей декомпозиции.

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

Из того, что const T& – это лишь read-only view не следует тот поток бреда, который вы процитировали

Превосходно. Сначала ты признаешь, что ссылочные значения не должны подлежать семантике константности своего контейнера, потом пишешь «можно, но это будет ужасно и тебя все проклянут», а когда я тебя тыкаю в тот факт, что больше половины контейнеров STL таки распространяет константность на свои ссылочные поля — скатываешься в «поток бреда, который вы процитировали».

Чтобы запретить копирование не обязательно вручную выписывать delete для конструкторов/операторов копирования

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

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

А «выбирать удобные инструменты» в этой школе не учат?

Вам это может быть неочевидно, но для каких-то задач C++ все еще удобный инструмент. Уж всяко удобнее чистых С-ей. Местами удобнее и Rust-а (по крайней мере для меня, как для любителя ООП).

Да, я предпочитаю писать софт, а не разбираться с инструментом.

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

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

Сначала ты признаешь, что ссылочные значения не должны подлежать семантике константности своего контейнера.

Я говорю о том, что константность в C++ не транзитивна при использовании ссылок/указателей. Т.е. константный объект может держать неконстантную ссылку/указатель на неконстантный объект.

что больше половины контейнеров STL таки распространяет константность на свои ссылочные поля

Э… Мне как бы это не очевидно.

скатываешься в «поток бреда, который вы процитировали».

Посмотрим еще раз на процитированный «поток бреда»:

Это работает только при условии, что «объект тип T» является тривиальным, у него нет динамического выделения ресурсов, ссылок, и прочих очень популярных среди кодеров на C/C++ штучек. Правда, в таких случаях зачастую можно просто копировать значение и не париться вообще, поскольку компилятор выоптимизирует копирование. Иначе получаем read-only view, через который можно изменить какую-то часть объекта, но не всегда, и прочие радости жизни, которые становится тем веселее, чем сложнее объекты.

Я вообще не могу понять, как утверждение «const T & – это не гарантия иммутабельности объекта типа T, а всего лишь read-only view на объект типа T» ведет вот этому вот. В частности:

работает только при условии, что «объект тип T» является тривиальным

получаем read-only view, через который можно изменить какую-то часть объекта, но не всегда

прочие радости жизни, которые становится тем веселее, чем сложнее объекты

Да, и про «факт, что больше половины контейнеров STL таки распространяет константность на свои ссылочные поля» здесь нет ни слова.

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

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

Эта «эрудиция» называется «десять лет опыта коммерческой разработки на трех ЯП, из них шесть на крупном проекте-миллионнике», это не считая всякие там хаскели, SQL, и питон, для которого я писал свою либу, но толком сам на нем ничего серьезного не делал, кроме всякой мелкой скриптоты/тестов.

И ничего увлекательного в том, что приходится на пальцах разъяснять заблуждения byko3y нет

Вот тут я полностью согласен: C++ настолько сложен, что даже такая банальная вещь, как const, требует 10 страниц обсуждения на LOR. Вот ты никогда не найдешь настолько сложного const ни в одном ЯП, ну не о чем 10 страниц говорить о const в каком-нибудь паскале или JS.

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

Зачем писать

static const uint32_t literal_length_values[max_literal_length_codewords] = { literal(0), literal(1), literal(2), literal(3),

Если можно

static const uint32_t literal_length_values[max_literal_length_codewords] = { 0_r, 1_r, 2_r, 3_r,}

Это к вопросу о знании языка, на котором ты пишешь

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

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

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

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

А вообще такой массив скорее всего можно заполнить через constexpr, и тогда эта простынь вообще свернётся

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

даже такая банальная вещь, как const, требует 10 страниц обсуждения на LOR

Чем больше общаюсь с вами, тем больше убеждаюсь, что сложность C++ тут не при чем, от слова совсем.

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

Возьмите какой-нибудь нетривиальный алгоритм сортировки или архивации. Как их ни декомпозируй - всё равно придётся мозг сломать. Вам придётся сделать нечеловеческое усилие и удерживать детали. В данном случае может даже удобнее будет, если весь код в одном месте. Понятно, что дублирующиеся куски и тут надо выносить в отдельные функции

Я не пытаюсь отписываться по поводу этой темы, потому что я слишком давно и слишком хорошо с ней знаком, пока что я ограничивался примерно тем, что «не так важно, сколько строк в функции».

Магнус Карлсен может играть вслепую на трех досках одновременно. Это талант плюс тренировка. Не каждый человек сможет научиться так играть, у большинства мастеров есть трудности при игре вслепую даже на одной доске.

Так вот проблема в том, что если, грубо говоря, сделать «игру вслепую на трех досках» работой, то заменить Магнуса Карлсена кем-то будет весьма проблематично. Возможно, но проблематично. Ну типа я работаю над тем, чтобы писать код намного проще, чем я могу на пределе, но массовые программисты все равно воют.

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

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

Я не пытаюсь отписываться по поводу этой темы, потому что я слишком давно и слишком хорошо с ней знаком, пока что я ограничивался примерно тем, что «не так важно, сколько строк в функции».

Я знаком чуть лучше, но вывод у меня противоположный: это очень важно

https://ru.m.wikipedia.org/wiki/Цикломатическая_сложность

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

Я знаком чуть лучше, но вывод у меня противоположный: это очень важно
https://ru.m.wikipedia.org/wiki/Цикломатическая_сложность

И при чем тут цикломатическая сложность? Она не зависит от формы программы.

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

Цикломатическая сложность зависит от лапшеобразности программы. Декомпозиция на отдельные функции, а потом и группировка этих функций по разным файлам — как раз способ бороться с лапшой.

А так конечно, можно хоть всю логику писать в int main () {}, кто ж запретит?

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

что больше половины контейнеров STL таки распространяет константность на свои ссылочные поля

Э… Мне как бы это не очевидно

Ну я не спорю, картина привычная: говно, костыли, костыли, говно, говно. «Хорошо в селе родном, пахнет сеном...». Я просто не устаю поражаться рассказам про «мне тут хорошо, уютно».

Я вообще не могу понять, как утверждение «const T & – это не гарантия иммутабельности объекта типа T, а всего лишь read-only view на объект типа T» ведет вот этому вот

получаем read-only view, через который можно изменить какую-то часть объекта, но не всегда

Дело в том, что у C++ неконтролируемые побочные эффекты. Это значит, что у вызова некой функцию с неким объектом в качестве аргумента эффект может быть ЛЮБЫМ, независимо от типов аргументов. Передали «const * const this», функция поменяет связанный non-const объект, связанный non-const объект думает, что владеет объектом по адресу this, на который у него non-const ссылка, поменяет этот объект — и по итогу вызов константного метода привел к изменению объекта. С ростом сложности картина становится хуже, поскольку уже никто из команды не сможет сказать, может ли привести вызов некоего константного метода к мутации this или нет, поскольку один объект ссылается на другой, другой ссылается на третий, третий ссылается на десятый. Именно потому «можно изменить какую-то часть объекта, но не всегда».

https://godbolt.org/z/qhjfaeT5M

Здесь у константного объекта вызывается константный метод, и, о чудо, объект меняется. Никаких const_cast, никаких mutable, только ловкость рук и никакого мошенничества.

Да, и про «факт, что больше половины контейнеров STL таки распространяет константность на свои ссылочные поля» здесь нет ни слова

Может быть я немного непонятно сказал. Суть в том, что std::vector предоставляет к массиву такой интерфейс, будто массив имеет модификатор const. Но этот массив под капотом не является const. То есть, транзитивная константность, по крайней мере для отдельных контейнеров. А ты, между прочим, обосрал мою идею про транзитивную константность:

юнионы в C++ (комментарий)

И не надо мне рассказывать, что std::vector не дает публикует значение/ссылку на значение своих полей — он дает ссылки на адреса в этом массиве, а нулевой элемент — это и есть сам массив.

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

Цикломатическая сложность зависит от лапшеобразности программы. Декомпозиция на отдельные функции, а потом и группировка этих функций по разным файлам — как раз способ бороться с лапшой

Если ты лапшу порубишь на мелкие кусочки, то у тебя получится порезанная лапша — вот и вся история. Особенно группировка по файлам вообще никак не влияет на цикломатическую сложность, поскольку не влияет на сам алгоритм.

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

Если ты лапшу порубишь на мелкие кусочки, то у тебя получится порезанная лапша — вот и вся история

Именно этим я здесь и занимаюсь: рублю твою лапшу

Особенно группировка по файлам вообще никак не влияет на цикломатическую сложность, поскольку не влияет на сам алгоритм.

Зато от группировки по файлам зависит алгоритм (пере-)компиляции и линковки C++

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

Я просто не устаю поражаться рассказам про «мне тут хорошо, уютно».

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

что больше половины контейнеров STL таки распространяет константность на свои ссылочные поля

Давайте примеры.

Дело в том, что у C++ неконтролируемые побочные эффекты.

Афигеть, открытие. «А на третий день Зоркий Глаз заметил…»

и по итогу вызов константного метода привел к изменению объекта

Какого объекта? В вашем примере нет изменения константных объектов.

С ростом сложности картина становится хуже

Опять словеса про «сложность». Хватит щеки надувать, есть примеры – показывайте. А если нет, то можете тешить себя иллюзией о том, что ваши 10 лет опыта что-то да значат.

https://godbolt.org/z/qhjfaeT5M

Здесь у константного объекта вызывается константный метод

Вы запутали сами себя. У вас ни экземпляр Container не константен, ни экземпляр Const в Container не константен.

Ну а то, что вы в const засунули мутабельные операции, так кто ж вас заставлял.

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

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

Так что вынужден повторить: «Доктор, когда я делаю вот так, то мне больно. А вы не делайте так».

Может быть я немного непонятно сказал.

В очередной раз и не немного.

Суть в том, что std::vector предоставляет к массиву такой интерфейс, будто массив имеет модификатор const. Но этот массив под капотом не является const.

Повторю еще раз: потроха реализации vector имеют к видимой семантике лишь косвенное отношение.

eao197 ★★★★★
()
Последнее исправление: eao197 (всего исправлений: 1)
Ответ на: комментарий от Crocodoom

Зато от группировки по файлам зависит алгоритм (пере-)компиляции и линковки C++

И при чем тут цикломатическая сложность? Не я ведь про нее разговор начал.

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

Ну а то, что вы в const засунули мутабельные операции, так кто ж вас заставлял

Нетранзитивность константности и воображаемая сложность заставили. К слову, я дергаю мутабельная операцию ДРУГОГО объекта. Если константность объекта не приводит к константности объектов, на которые он ссылается, то что мне помешает из константного метода вызвать неконстантный метод другого объекта? Только честное слово.

Потому что транзитивную константность можно сделать там, где это реально нужно

std::string какое-то время была copy-on-write. И что же, оно стало «нереально нужно» — потому его убрали? Или же число UB и число лишних копирований стало слишком велико и средствами языка с этим ничего нельзя было сделать? И тогда это уже не «где реально нужно», а «где получилось». GC в C++ реально нужен, но сделать его никому не получилось. Вот это то, что я лично понимаю под «принять язык таким, какой он есть».

Повторю еще раз: потроха реализации vector имеют к видимой семантике лишь косвенное отношение

Ну да, «делаю что хочу». Я как бы об этом и пишу. В принципе, никто не мешал авторам STL наделить контейнера вообще произвольной семантикой — любиться с ними бы пришлось лишь немножечко больше, чем сейчас.

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

Нетранзитивность константности

Это объективная реальность.

воображаемая сложность заставили.

А это ваши собственные тараканы.

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

Здравый смысл. Если у вас в константном объекте хранятся неконстантные ссылки/указатели на другие объекты, значит это вам зачем-то нужно. И очевидно, вам это нужно чтобы дергать неконстантные методы этих самых других объектов.

Так что здесь вопрос не о честном слове, вопрос о том, зачем вам в объекте A иметь неконстантный указатель на объект B.

И что же, оно стало «нереально нужно» — потому его убрали?

Насколько я помню эту историю, сперва выяснилось, что это не так эффективно, как казалось изначало. А потом CoW для string стал противоречить требованиям стандарта C++11.

GC в C++ реально нужен

Нет. Язык C++ ценен именно тем, что GC в нем нет. Кому нужен язык с GC, тот может выбрать из кучи альтернатив.

В принципе, никто не мешал авторам STL

В принципе, никто не мешал вам привести примеры того «что больше половины контейнеров STL таки распространяет константность на свои ссылочные поля». Чтобы можно было понять о чем таки вы бредите.

Но вы в очередной раз не смогли в конкретику.

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

Нетранзитивность константности и воображаемая сложность заставили. К слову, я дергаю мутабельная операцию ДРУГОГО объекта. Если константность объекта не приводит к константности объектов, на которые он ссылается, то что мне помешает из константного метода вызвать неконстантный метод другого объекта? Только честное слово.

Ты действительно не осиливаешь сделать транзистивную константность? Или просто троллишь? Я вот на коленках в несколько строк сделал https://godbolt.org/z/rqf5ba5dr.

Можешь сувать эту обертку Tconst в любой вектор и ещё куда надо. Хотя в врядли тебе это нужно, бессмысленный теоретический скулеж.

kvpfs ★★
()
Последнее исправление: kvpfs (всего исправлений: 1)
Ответ на: комментарий от byko3y

GC в C++ реально нужен, но сделать его никому не получилось.

Есть C++/CLI со сборкой мусора: https://ru.wikipedia.org/wiki/C%2B%2B/CLI

Но он скорее не нужен, C++/CLI поддерживает только С++17 и пользователям рекомендовано переходить на С++, хотя и есть просьбы не бросать С++/CLI и добавлять туда современные стандарты…

Также многие GC написаны на С++, вот для примера:

  1. WebKit’s JavaScriptCore: https://webkit.org/blog/7122/introducing-riptide-webkits-retreating-wavefront-concurrent-garbage-collector/

  2. Chromium’s Blink GC: https://v8.dev/blog/high-performance-cpp-gc

  3. Firefox’s SpiderMonkey JavaScript engine: https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/Internals/Garbage_collection

  4. LuaJIT gc: http://wiki.luajit.org/New-Garbage-Collector

fsb4000 ★★★★★
()
Последнее исправление: fsb4000 (всего исправлений: 1)
Ответ на: комментарий от eao197

Так что здесь вопрос не о честном слове, вопрос о том, зачем вам в объекте A иметь неконстантный указатель на объект B

Тип объекта контейнера A может быть константен и неконстантен одновременно, сидя в той же переменной. А вот тип ссылки на объект B не может просто так поменяться. Если non-const A ссылается на non-const B, то и const A будет ссылаться на non-const B. Другое дело, что эта проблема решаема парой геттеров, возвращающих ссылку на B с нужной константностью — но это уже не совсем простое решение, особенно когда у тебя не hello world. Собственно, бесконечные стены из таких прокладок в STL тому доказательство.

Насколько я помню эту историю, сперва выяснилось, что это не так эффективно, как казалось изначало. А потом CoW для string стал противоречить требованиям стандарта C++11

Да, я именно об этом и пишу — оно копировалось, и избавиться от этого никак не получилось. Язык тупо не позволяет. Аналогичная история с GC.

В принципе, никто не мешал вам привести примеры того «что больше половины контейнеров STL таки распространяет константность на свои ссылочные поля». Чтобы можно было понять о чем таки вы бредите

Ну было же выше по треду, что vector, string, list распространяют, shared_ptr, reference_wrapper — нет. Всё, конкретика?

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

Есть C++/CLI со сборкой мусора

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

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

Если non-const A ссылается на non-const B, то и const A будет ссылаться на non-const B.

Да. И если вы в A храните неконстантную ссылку на B, значит вам принципиально важно иметь именно что неконстантную ссылку.

Все.

Последующие стенания – это все какое-то неасиляторство в квадрате.

Да, я именно об этом и пишу — оно копировалось, и избавиться от этого никак не получилось. Язык тупо не позволяет.

Вы пишите вот это:

std::string какое-то время была copy-on-write. И что же, оно стало «нереально нужно» — потому его убрали? Или же число UB и число лишних копирований стало слишком велико и средствами языка с этим ничего нельзя было сделать?

Так вот к убиранию CoW реализаций std::string ни количество UB, ни количество «лишних копирований» (чтобы под этим не подразумевалось) не имеет отношения. Так что вы опять высрали какую-то чухню, которую фиг знает как можно привязать к предыдущим вашим словами.

контейнеров STL

shared_ptr, reference_wrapper

shared_ptr и reference_wrapper уже стали контейнерами?

Пилять, есть ли еще где-то какое-то дно, которое вы еще не пробили?

eao197 ★★★★★
()

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

Я сюда боьше не ходок, чего и вам желаю, незачем кормить его.

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

Зато от группировки по файлам зависит алгоритм (пере-)компиляции и линковки C++

И при чем тут цикломатическая сложность? Не я ведь про нее разговор начал.

wiki: Математически цикломатическая сложность структурированной программы определяется с помощью ориентированного графа, узлами которого являются блоки программы, соединенные рёбрами, если управление может переходить с одного блока на другой. Тогда сложность определяется как:

M = E − N + 2P, где:

M = цикломатическая сложность, E = количество рёбер в графе, N = количество узлов в графе, P = количество компонент связности

Узлы = программные модули; рёбра = зависимости между модулями.

В С++ модульность реализована через файлы, поэтому модули ~ файлы в данном случае (заголовки и имплементация). Как там сделаны модули в С++20 я хз

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

незачем кормить его.

Кстати, да.

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

eao197 ★★★★★
()
Последнее исправление: eao197 (всего исправлений: 1)
Ответ на: комментарий от byko3y

Если ты лапшу порубишь на мелкие кусочки, то у тебя получится порезанная лапша — вот и вся история.

Ничего вы не понимаете в «лапше» и «нарезке». Бывает «лапша» в сурсах и не поддающаяся нарубке.

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

Эту реализацию какой-то маньяк-перфекционист делал, в хорошем смысле слова. Читается тяжеловато из-за обилия ifdef-ов, inline-ов, функций в одну строчку и прочих ухищрений. Но, вероятно, оптимизировано идеально.

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

Поразительно то, что почти полгода назад я писал DarkEld3r-у про const примерно то же самое

Мне, конечно, лестно, что ты уже который раз меня в этой теме вспоминаешь, но в чём смысл этого аргумента? Ну то есть, что ты говорил это именно мне.

не используйте const в локальных переменных, это overkill, вы и так видите все использования этих переменных;

Ну это такое себе. Не хочу спорить с остальными моментами - всё равно ничего нового тебе не скажу. Но вот этот аргумент звучит как «я внимательный - ошибок не сделаю». И мы прекрасно знаем, что это не работает. Я бы ещё понял, если бы аргумент звучал как «ошибочных изменений локальных переменных не бывает» или «такое ошибки легко отлавливаются». А так выглядит как противопоставление минимальных усилий (ну в самом деле: условное const auto написать не особо сложнее) внимательности человека.

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

Так вот к убиранию CoW реализаций std::string ни количество UB, ни количество «лишних копирований» (чтобы под этим не подразумевалось) не имеет отношения. Так что вы опять высрали какую-то чухню, которую фиг знает как можно привязать к предыдущим вашим словами

Э, погоди, что тогда ты подразумевал под «это не так эффективно»? Что там еще не так эффективно может быть? Взятие ссылки на символ строки неэффективно делалось?

shared_ptr и reference_wrapper уже стали контейнерами?

Но unique_ptr на 1000% контейнер, по любой религии, какую бы ты не исповедовал. А иначе std::vector не является «контейнером», поскольку тоже ссылается на значения — это указатель на вектор, а не сам вектор.

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

Дело в том, что у C++ неконтролируемые побочные эффекты. Это значит, что у вызова некой функцию с неким объектом в качестве аргумента эффект может быть ЛЮБЫМ, независимо от типов аргументов.

Для таких вещей есть соглашения о коде и документация.

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

Дело в том, что у C++ неконтролируемые побочные эффекты. Это значит, что у вызова некой функцию с неким объектом в качестве аргумента эффект может быть ЛЮБЫМ, независимо от типов аргументов.

Для таких вещей есть соглашения о коде и документация

Вот именно, const — это документация, которую частично может проверить компилятор, но оставшаяся часть проверки лежит на тебе, ты должен сам убедиться (через доки и сорцы), что вызов константного метода не приведет к изменению объекта.

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

Ничего вы не понимаете в «лапше» и «нарезке». Бывает «лапша» в сурсах и не поддающаяся нарубке

Ты недооцениваешь мотивированности говокодеров.

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

const означает что код обращающийся к переменной с этим модификатором будет обращаться только для чтения и не более того. Это не означает константность объекта и то, что какой-нибудб друго код не будет записывать что-нибудь в жту же переменную.

И это штатное поведение C++ безо всяких кастов с убиранием const. const просто означает что я не буду ничего писать в эту переменную.

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

Мне, конечно, лестно, что ты уже который раз меня в этой теме вспоминаешь, но в чём смысл этого аргумента? Ну то есть, что ты говорил это именно мне

Основной аргумент — «полгода назад я еще меньше знал C++, но с тех пор проблема не стала менее актуальной». От того, что «я десять лет пишу на крестах» проблема меньше не становится — ее просто перестаешь замечать.

не используйте const в локальных переменных, это overkill, вы и так видите все использования этих переменных

Я бы ещё понял, если бы аргумент звучал как «ошибочных изменений локальных переменных не бывает» или «такое ошибки легко отлавливаются». А так выглядит как противопоставление минимальных усилий (ну в самом деле: условное const auto написать не особо сложнее) внимательности человека

Согласен. Я сейчас потыкал разные варианты оптимизаций const/non-const, и не нашел проблем при использовании const. То есть, например, copy elision происходит при возврате константной локальной переменной (NRVO), даже несмотря на то, что тип возвращаемого объекта неконстантный.

byko3y ★★★★
()
Последнее исправление: byko3y (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.