psilogic: (Default)
[personal profile] psilogic
[ Предупреждение: для непрограммистов неинтересно ]

Пусть у нас есть два класса - базовый Base и отнаследованный от него Derived. В Derived есть конструктор, похожий на конструктор копии с параметром типа Base.

class Base
{
...
};

class Derived: public Base
{
public:
    Derived() {...}
    Derived(const Base &b) { /* важные манипуляции */ }
};


Допустим, в программе это используется вот так:

Derived d1;
Derived d2(d1);


И оно не работает.

Тщательное расследование показало эпическое западло...



В какой-то момент я внес часть кода в функцию:

void foo(Base &d1)
{
    Derived d2(d1);
    ...
}
...
Derived d1;
foo(d1);



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

Западло состоит в том, что в строке Derived d2(d1) не всегда вызывается второй конструктор и не будут выполняться "важные манипуляции". Вместо этого будет вызван "невидимый" автоматически сгенерированный конструктор-копии, и все поля будут тупо скопированы из d1 в d2.

Это происходит в том случае, если d1 имеет тип Derived. Если Base - то все хорошо. Вот почему та функция исправляла проблему. Так тоже будет работать:

Derived d2((Base&)d1);


Лечится это легко:

class Base
{
...
};

class Derived: public Base
{
public:
    Derived() {...}
    Derived(const Base &b) { /* важные манипуляции */ }
    Derived(const Derived &b) { /* важные манипуляции */ }
};


Но ведь и вляпаться тоже легко...

Date: 2009-07-17 08:48 pm (UTC)
From: [identity profile] psilogic.livejournal.com
[ А вот если как это у меня пару раз было - звонок в 5-6 утра от службы поддержки со срочным вызовом, потому что система, работающая в режиме 24х7 дала сбой. ]

Ну допустим, ты делаешь такую систему. Время разработки в любом случае ограничено. Лучше потратить его на исключение тех неприятностей, которые потенциально более опасны, чем другие. Я призываю фокусироваться на предотвращении тех потенциальных неприятностей, которые реально опасны, а не в воображении. Если ты пишешь систему "с риском для жизни", то тем более лучше тратить время не на "рюшечки" типа писать везде const, а не enum потому, что атэц Майерс сказал, что enum - это "трюк". И если не связано с риском для жизни, все равно выкаблучиваться не надо: время - деньги.

[ Перенос из sub_project1 в sub_project2 - "копи-паст". ]

А везде заменять sub_project1::name_t на sub_project2::name_t будет батька Махно?

[ Неправильно с твоей точки зрения. Автор имеет право на свою точку зрения? ]

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

[ Автор внятно объяснил преимущества своего подхода. Ему важнее скорость работы, меньший расход памяти, более расширенная функциональность. ]

Остапа понесло. Какая разница по скорости работы и расходу памяти между const, enum и define в конкретном случае с определением числовых констант? Ну-ка, просвети меня, как "дополнительная строчка в файле реализации" ускоряет исполнение программы?

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

Лень - это святое.

[ Тебе все равно что скрыто под капотом компилятора (что видно из твоего первого очкового анализа), главное чтобы букф было поменьше. ]

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

[ Ты слово "если" видишь? Или для тебя "если" - это утверждение? ]

Если - это наезд. Например, "если ты, Бсивко, мудак, то ты, Бсивко, мудак". Утверждение логически безупречно (тавтология из A следует A) и не содержит, формально говоря, утверждения, что Бсивко - мудак. Но я сомневаюсь, что оно тебе было бы приятно.

[ У меня вопрос главный то в этом ]

Да, конечно настаиваю. На самом деле одна конкретная фишка с константами - мелочь, которую можно списать на некоторое "эстетство" автара. Если бы она была одна. Это просто тебе захотелось очень подробно обсуждать эту мелочь. Но я сразу, взяв только одну главу и начав ее читать, наткнулся еще на пару вещей, посмотрел на общий "йазыг" и стиль - и мне не понравилось. Считаю, что книжка вредная для обучающихся. На свое мнение я тоже имею право, так как вожусь с этим языком по времени, наверное, не меньше, чем сей афтар.

Date: 2009-07-17 11:16 pm (UTC)
From: [identity profile] bsivko.livejournal.com
>Лучше потратить его на исключение тех неприятностей, которые потенциально более опасны, чем другие. Я призываю фокусироваться на предотвращении тех потенциальных неприятностей, которые реально опасны, а не в воображении.

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

>время - деньги
качество/время = результат ~= деньги

>А везде заменять sub_project1::name_t на sub_project2::name_t будет батька Махно?

Я не говорю о внешнем вызове, а о внутреннем использовании.

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

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

>Остапа понесло. Какая разница по скорости работы и расходу памяти между const, enum и define в конкретном случае с определением числовых констант? Ну-ка, просвети меня, как "дополнительная строчка в файле реализации" ускоряет исполнение программы?

Там жеж в книжке написано. Ты же сам говорил что её не х.ем по заголовкам читал, а как следует, с толком и расстановкой.
Цитирую (это к вопросу о памяти):
"К тому же в случае использования константы с плавающей точкой (как в этом примере) генерируется более компактный код, чем при использовании #define. Дело в том что препроцессор, слепо подставляя вместо макроса ASPECT_RATIO величину 1.653, создает множество копий 1.653 в объектном коде, в то время как использование константы никогда не породит более одной копии этого значения."

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

Почему хуйню? Смотрим пост http://psilogic.livejournal.com/326131.html?thread=6217203#t6217203 - где отмечены особенности (или самые важные (если о других было лень писать), или тебе известные (на то время) ).
Были затронуты вопросы:
1 - кол-во букф, область видимости.
2 - удобство отладки в IDE, область видимости.
3 - кол-во букф, необходимость переключаться между файлами (хотя я называю это сущестованием сущности в двух местах, что имеет среднюю степень критичности).

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

Итаг, что в моем обосновании является хуйней? Ткни пальчиком, плз.

>Если - это наезд. Например, "если ты, Бсивко, мудак, то ты, Бсивко, мудак". Утверждение логически безупречно (тавтология из A следует A) и не содержит, формально говоря, утверждения, что Бсивко - мудак. Но я сомневаюсь, что оно тебе было бы приятно.

Ну извини.

Теперь обоснование конкретно в моем контексте.
Мне бывает пофигу на строгую типизацию. Например, мою табличку ICQ Rating генерит простой скрипт на перле, написанный за два часа и занимает он пару страниц кода. Скрипт маленький, ошибки сделать трудно, а если есть - то отладить лехко, в реальные системы код не пойдет - домашнее использование. Потому нечего его писать на С++, есть более удобные инструменты.

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

А у тебя по моей видимости (в данный момент это мое мнение) имеется религиозно-идеологический штамп - "отсутствие строгой типизации означает что йа мудаг."

Я понятно объяснил, что на момент написания ничего подобного про мудака я не имел ввиду?

Date: 2009-07-18 08:11 am (UTC)
From: [identity profile] psilogic.livejournal.com
[ Реально опасны это те, которые уже дали по голове? ]

Это как раз твой подход - ты однажды головкой ударился, и до сих пор глаза косят (на #define-ы) :)

[ качество/время = результат ~= деньги ]

Если скажешь, что я собираюсь жертвовать качеством, то пойдешь на хуй. Но временем я тоже жертвовать не хочу. Как раз наоборот: используя более экономные (по времени) методы кодирования, можно больше времени оставить на отладку-полировку. Надо искать оптимум. И ты функциональность забыл - третий ключевой фактор.

[ Я не говорю о внешнем вызове, а о внутреннем использовании. ]

Внутри using-и придется переименовывать.

Допустим, ты использовал одно и то же название класса в субпроектах 1 и 2. namespace-ы красиво помогли избежать конфликтов. Казалось бы. Но стоит тебе скопипастить этот класс из одного проекта в другой, как начнутся конфликты. И тогда тебе придется заниматься переименованиями. Причем, процесс переименования может оказаться геморройным, так как в некоторых случаях будет неочевидно, какой из классов используется - от проекта 1 или от проекта 2, так как строка на замену у тебя перед глазами в середине файла, а using где-то в начале файла и вне экрана. А сложные названия с уникальными префиксами можно переименовать за пару секунд в автоматическом режиме find/replace.

Так что тут одна вещь исключает другую. Либо ты допускаешь одинаковые имена - и тогда твой прием копипаста класса не дает выгоды. Либо ты не допускаешь одинаковые имена - но тогда namespace-ы не нужны.

[ Цитирую (это к вопросу о памяти): ]

А к вопросу о скорости, значит, тебя таки несло без пургена?

Про память написано нечто странное, мягко говоря. Поясняю.

Пусть есть оператор a += c, где c - числовая константа. Компилятор может преобразовать это в ассемблерную команду, где константа лежит с сегменте кода, составляя часть команды (add или fadd). Каждый (a += c) будет генерировать такую команду и очередную копию константы.

А также компилятор может завести переменную в сегменте данных и в ассемблерной команде сослаться на нее. При этом ему придется включить в команду адрес константы. Адрес будет лежать в сегменте кода - в дополнение к константе в сегменте данных. Каждый (a += c) будет генерировать такую команду (add/fadd) и очередную копию адреса константы, сама константа при этом может не копироваться. При этом есть одна неприятность: команда должна обращаться и к сегменту кода, и к сегменту данных, что теоретически ведет к замедлению. Но это только теоретически - реально там тонна факторов, которые могут все снивелировать.

Таким образом, придется многократно копировать либо адреса, либо константы. Поскольку речь идет о числовых переменных, то объемы адресов и констант сопоставимы, иногда будет экономия при первом способе, иногда - при втором.

Худший случай для первого способа - это константа типа double, long double или long long при 32-разрядной адресации. Тогда адрес был бы короче, давая выигрыш 4-6 байт на каждую команду. Худший случай для второго способа - константа char или unsigned char при 64-разрядной адресации. Тогда адрес был бы длиннее, давая уже проигрыш в 7 байт на каждую команду плюс необходимость лезть в сегмент данных.

Но! Все, что я написал, относится и к const, и к define, и к enum. Для всех трех случаев компилятор может использовать и первый способ, и второй. Для второго способа компилятор должен заметить, что используется одна и та же константа - он это сделает либо, сравнивая имена, либо, сравнивая литералы - что в лоб, что по лбу.

Так где там экономия по объему?

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

Досье сравнил - первые упоминания C++ относятся к 1990 году. В это время я был на 2-3 курсе института, и как раз торчал в комп. классе, ковыряясь с Turbo C, и только что появившимся Borland C++ 1.0 под MS-DOS. Только статеек не писал :)

Date: 2009-07-19 02:29 am (UTC)
From: [identity profile] bsivko.livejournal.com
>Если скажешь, что я собираюсь жертвовать качеством, то пойдешь на хуй. Но временем я тоже жертвовать не хочу. Как раз наоборот: используя более экономные (по времени) методы кодирования, можно больше времени оставить на отладку-полировку. Надо искать оптимум. И ты функциональность забыл - третий ключевой фактор.

Знаю таких "оптимутмистов". После которых проектный код проще просто выкинуть и написать нормально. Уже не в первый раз сталкиваюсь и не только на С++. Потому что вылетают ошибки из ниоткуда, память протекает абы как и приложение держит нагрузку в единицы транзакций в секунду вместо потенциальных сотен и тысяч. Это разница между экономичным и профессиональным кодом. Когда проект делается не впопыхах к вчера, а с соблюдением всех фаз и проверок на всех этапах.

Что ты хотел сказать про функциональность?

>.. А сложные названия с уникальными префиксами можно переименовать за пару секунд в автоматическом режиме find/replace.

Ещё раз: find/replace для внешних сущностей делается и там, и там. Для внутренних он необходим для define, для namespace он уже не нужен.

Разница define и namespace - именно в том, что define - это препроцессор, не относящийся к языку никаким боком. namespace - это языковое средство, которое контролирует, использует и понимает уже не только программист, но и компилятор.

И различных особенностей и преимуществ namespace много. Например, подключили библиотеку X и библиотеку Y, и оказалось, что в них конфликт имен Z. Для namespace проблема решается легко:
namespace X {
#include X
}
namespace Y {
#include Y
}

X::Z
Y::Z

что же ты будешь делать с #define?

Или например namespace имеют свойство вложенности. Когда текущий проект можно моментально сделать подпроектом одним namespace.

Я не специалист по холиварам и всех особенности и того и другого не назову. Для этого есть умные книжки и справочники. То, что в С++ систематически убивается препроцессор, ясно и понятно уже давно. Есс-но этому сопротивляется С-ишное старье и привычки. Отношение создателя С++ к препроцессору очень хорошо показано в главе "18. Препроцессор С" книги "Дизайн и эволюция С++" Страуструпа (с примерами, особенностями и инструментами замены). И это не идеология. А естественный процесс отмирания атавизма.

>Пусть есть оператор a += c, где c - числовая константа. Компилятор может преобразовать это в ассемблерную команду, где константа лежит с сегменте кода, составляя часть команды (add или fadd).
>А также компилятор может завести переменную в сегменте данных и в ассемблерной команде сослаться на нее.

Ключевой момент в том, что компилятор может. Он знает, что сущность - константа, а после define'а он может об этом только догадываться. Поэтому в случае константы у компилятора есть выбор и он может с'опитимизировать работу программы как в сторону экономии памяти, так и в сторону ускорения работы.

>А к вопросу о скорости, значит, тебя таки несло без пургена?

const std::string c_str("ABC");

#define C_STR std::string("ABC")

В каждом define сработает конструктор. В const объект создается один раз.

И это оченьвидный пример. Но главное, что компилятор знает, что константа - это одинаковая неизменяемая сущность во многих кусках кода, а define для него - это фигня, разбросанная по всему коду, о сущности которой можно только догадываться. Поэтому основное правило заключается в том, что чем больше компилятор знает о коде, тем об лучше сможет его с'оптимизировать.

>Но! Все, что я написал, относится и к const, и к define, и к enum. Для всех трех случаев компилятор может использовать и первый способ, и второй.

"Шушпанчики могут работать 365 дней в году. Но не работают." (с)

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

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

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

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

Date: 2009-07-19 09:12 am (UTC)
From: [identity profile] psilogic.livejournal.com
[ Знаю таких "оптимутмистов". ]

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

[ const std::string c_str("ABC"); ]

Речь шла о числовых константах, у тебя склероз что ле?

[ В современных процессорах необходимые данные на последующую команду загружаются для последующей обработки заранее. ]

Америку, блядь, открыл...

[ Но главное, что компилятор знает, что константа - это одинаковая неизменяемая сущность во многих кусках кода, а define для него - это фигня, разбросанная по всему коду, о сущности которой можно только догадываться ]

Для компилятора нет define, препроцессор уже подставил вместо имени define число. А одно и то же число - это сущность неизменяемая. Короче, не строй из себя идиота.

Date: 2009-07-19 10:46 am (UTC)
From: [identity profile] bsivko.livejournal.com
Опять ругаться начал. Нервы уже не те, да?

>Речь шла о числовых константах, у тебя склероз что ле?

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

В любом случае если имеются какие-либо действия по конструированию элемента, они произойдут при использовании define. При const этого нет.

Придумай себе класс числовых значений (например комплексных/рациональных или ещё каких чисел) и получишь соответствующий результат.

>Америку, блядь, открыл...

Для тебя похоже что открыл. Т.к. ты рассуждаешь тут теоретически, а на самом деле во многом все зависит и от компилятора, и от харда. И "в среднем" специалисты говорят, что const позволяет работать быстрее и использовать меньше памяти.

Так что не строй из себя идиота.

Неудобные вопросы ты успешно проигнорил. Недостаток квалификации в предмете и дискуссии "компенсируется" квалификацией в полемике.

>Для компилятора нет define, препроцессор уже подставил вместо имени define число. А одно и то же число - это сущность неизменяемая. Короче, не строй из себя идиота

Это число ещё нужно найти и сопоставить его в различных кусках кода. Может ещё скажешь в каждом "for( int i =0; ..." компилятор где-то 0 хранит как одинаковое число? Фигвам.

Date: 2009-07-19 10:58 am (UTC)
From: [identity profile] psilogic.livejournal.com
[ Нет, я работаю с первоисточником. У Мейерса нет ни слова про числовые константы, их похоже выдумал ты. ]

Я ссылался на первоисточник, на страницы 29-30. Страница 29, читаем:

const double CostEstimate::FudgeFactor = 1.35;

Это не числовая константа?

Мое терпение иссякло. Пошел на хуй. За такое уебство я не баню, но общаться с таким говном вряд ли еще стану.

Date: 2009-07-19 11:49 am (UTC)
From: [identity profile] bsivko.livejournal.com
Это пример, на котором разбирается рекомендация.

Всего хорошего.

P.S.
— Вас не затруднит? Будьте любезны, передайте на билетик, пожалуйста! Спасибо.
— Ну ты, хрен, из интеллигентов, что ли?
— Да нет, что вы, я такое же быдло, как и вы!
(с) Вежливо

Date: 2009-07-19 11:52 am (UTC)
From: [identity profile] psilogic.livejournal.com
Вот поэтому Мейерс и ты с такими рекомендациями стройными рядами идете на хуй

Date: 2009-07-19 01:04 pm (UTC)
From: [identity profile] bsivko.livejournal.com
Мирослав, все хорошо. Мейерса забрали и унесли добрые санитары. Его идеологическая деятельность тебя больше не побеспокоит.

Знал бы такую реакцию, в спор бы не вступал. Здоровье (не только мое) оно того... дороже.

Сейчас ещё раз меня пошлют на всякий случай, и все будет нормально (;

Date: 2009-07-19 02:29 am (UTC)
From: [identity profile] bsivko.livejournal.com
>Досье сравнил - первые упоминания C++ относятся к 1990 году.

Это дата первой публикации. Мейерс занимался C++ с 1986-го года, когда во всем мире было порядка 2000 пользователей С++. "Effective C++" появился уже в 1991-м.

Date: 2009-07-19 09:05 am (UTC)
From: [identity profile] psilogic.livejournal.com
Ну получается время использования языка сопоставимо, так что можешь меня слушать столь же почтительно, как Мейерса :)))

Date: 2009-07-19 10:48 am (UTC)
From: [identity profile] bsivko.livejournal.com
Время, но не качество. Может ты хуи в подворотнях пинал сидел на каком-нить проекте в тысячу строк кода, то бишь в болоте, и не знал толком ничего о смежных областях и об изменении всего во времени.

И как писал, мне в данном случае (когда я сам далеко не чайник и даже не любитель в С++) на авторитеты пофиг. Я читаю обоснования, а не правила.

Date: 2009-07-19 10:54 am (UTC)
From: [identity profile] psilogic.livejournal.com
А может наоборот Мейерс хуи пинал, когда книжки не писал :)

Date: 2009-07-17 11:16 pm (UTC)
From: [identity profile] bsivko.livejournal.com
>Да, конечно настаиваю. На самом деле одна конкретная фишка с константами - мелочь, которую можно списать на некоторое "эстетство" автара.

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

>На свое мнение я тоже имею право, так как вожусь с этим языком по времени, наверное, не меньше, чем сей афтар.

На здоровье (;

Можно взглянуть на досье и сравнить? Если уж такая аппеляция пошла.
Page generated Aug. 31st, 2025 06:26 am
Powered by Dreamwidth Studios