Обновить
66
Андрей@DistortNeo

Математик, программист

24
Подписчики
Отправить сообщение
Скорее, в чём выражается сверхбезопасность, а не просто безопасность?

Рискну предположить, что безопасность по вычислениям заключается в отсутствии неявных преобразований типов, которые могут привести к потере точности или неоднозначному поведению, а также отсутствии прямого доступа к содержимому переменных: например, вычисление abs(float) можно делать просто сбрасывая старший бит в битовом представлении числа.
Это просто палка о двух концах.

1. Желающие производить продукт честно просто не выдерживают конкуренции на рынке.

2. Массовый отзыв лицензий поначалу приведёт к снижению производства и росту цен, а недовольство людей текущее правительство не переносит на дух.
Понятное дело, что сравнивать Java и C++ нельзя. А вот холивар Java vs C# был бы более интересен, особенно учитывая то, что глядя на код, не всегда легко понять, на каком языке он написан.

Я работаю преимущественно в науке, а не в продакшене. При этом мне больше нравится C#, потому что
1. Скорость эволюции C# как языка выше, чем у консервативной Java. Те же лямбды в Java появились только через 6 лет после C#. А мегаудобного для сетевых приложений асинхронного программирования в Java пока ещё нет.
2. Удобная визуальная среда для разработки GUI приложений в отличие от зоопарка GUI-библиотек в Java. А за счёт Mono — ещё и кросс-платформенная.
3. Удобная и быстрая IDE, бесплатная для некоммерческого использования.
4. Лёгкость подключения кода из нативных библиотек.

При этом я понимаю, что инфраструктура Java в целом более богата и свободна. Но пока она не нужна — .NET устраивает.
От задачи зависит. Обработку изображений, когда она является узким местом, разумнее писать не на Java, а на C++ с использованием SIMD (или даже GPU или Phi), т.к. разница по скорости — разы и даже десятки раз.

А вот для прототипирования хороши будут и MatLab, и Python.
Я не считаю это большой проблемой. Интерпретируемые языки ещё более медленные, тем не менее, они активно используются в серверном программировании.

Дело в том, что стоимость разработки ПО на Java ниже, чем на C++. Пока выгодно увеличивать мощность серверов, а не платить втридорога за быстрый код, ситуация будет именно такой.
Если не зашли в цикл подсчета энтропии — пусть выдает -NaN, получите exception при использовании результата

Вот в этом и заключается отличие debug и release версий.

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

Если добавить отключаемые assert (=debug версия), то ошибка поймается внутри вызова функции, дальше будет легко подняться по стеку.

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

Важно то, что как только речь пойдёт о промышленном производстве одежды с целью извлечения прибыли, то зингеры и золинги закономерно уступят своё место современным моделям.
Последний вариант: устройство, которое принимает сырой сигнал (не спектральный), накладывает избыточность (FEC), затем кодирует и передаёт на определённой длине волны (WDM). И умеет это делать в обратную сторону — декодировать и исправлять ошибки.
НЕТ. RTTI есть у классов без vTable.

Ну не умею я выражаться так, чтобы не цеплялись к словам. Хорошо, напишу так: корректная работа RTTI (возврат реального типа) требует наличия vtable у объекта.

GCC просто не скомпилирует интерфейсы.

Почему? C++ Builder позволяет объявлять интерфейсы как классы C++:

You can declare a class that represents an interface just like any other C++ class.

Ref: http://docwiki.embarcadero.com/RADStudio/Seattle/en/Inheritance_and_Interfaces#Declaring_Interface_Classes

ОШИБАЕТЕСЬ. Ещё раз, прочтите https://habrahabr.ru/post/181107/

Что мне мешает использовать интерфейсы без счётчика ссылок? Т.е. не использовать TObject и IUnknown в качестве базовых. Другое дело, что без счётчика ссылок действительно будет плохо.
Самая долгая операция в Собеле — это чтение/запись памяти, а не вычисления.
Во многих задачах вообще нет никакой необходимости в обработке альфы. Просто альфа игнорируется. Неэффективность (по назначению используется 75% ресурсов) компенсируется просто возможностью использования векторных операций.

В своих проектах для ряда задач я использую немного другое представление изображений: бью изображение на 4 подизображения и записываю с интерливингом. Таким образом, в каждом регистре у меня оказывается только одна компонента — не тратятся ресурсы на операции с альфой. Плюс полностью исчезает невыровненный доступ.
не надо путать vTable c RTTI.

Необходимое условие работы RTTI — наличие vtable. Собственно, по vtable однозначно определяется класс, а дальше дело техники.

ДА НУ? Вы хотите сказать, что если класс без виртуальных методов привести к базовому классу, то у него typeid будет равен базовому классу, а не наследнику?

Да. Именно так описано и в стандарте, и в MSDN (читайте на английском, русский перевод ужасно корявый):

The expression must point to a polymorphic type (a class with virtual functions).Otherwise, the result is the type_info for the static class referred to in the expression.

Так это СИНТАКСИС. А не семантика. Семантика там совсем другая.

Вот именно к этому я и шёл. Если я возьму кусок кода на C++ с множественным наследованием интерфейсов, то представление объекта в памяти после компиляции GCC и C++ Builder будет различным. Ну да, C++ Builder сделает интерфейс COM-совместимым, но для меня этот факт не имеет никакого значения.
Разные бывают задачи, разные. Если нет нужды писать код, совместимый со старыми компиляторами, то и не надо этого делать. Сейчас с поддержкой стандартов дела обстоят чуть лучше.

И выработать свой набор конструкций, одинаково работающий на всем зоопарке компиляторов с разницей в выпуске в 25 лет.

У меня возникало такое ощущение, когда я изучал файлы STL или Boost. Впрочем, и в них в последних версиях совместимость со старыми компиляторами совсем поломана.

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

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

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

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

До тех пор. пока вы привязаны к конкретному компилятору и конкретной железке, вы можете писать код, учитывая особенности конкретного компилятора и архитектуры. Если же вы хотите иметь переносимый код, то придётся отказаться от всего, что выходит за рамки стандарта языка.
Иными словами, приведение от AB к B должно выдать уникальный указатель, но по которому можно перейти к vTable ТИПОВЫМ способом.

Именно поэтому размещение в памяти при множественном наследовании обычно выглядит так, и мы оба это понимаем:

[vtableA*][A][vtableB*][B]

Метод, принимающий на вход A* и B*, будет получать разные адреса. Он не знает и не должен знать, является ли объект B частью чего-то или нет, отсюда и необходимость хранения указателя на vtable для каждого базового класса при множественном наследовании. Чуть интереснее обстоит дело при виртуальном наследовании — там добавляется ещё поле для хранения смещения, и оно тоже ест память.

А ещё есть такая штука, как приведение B* к AB*, то есть от базового класса к производному. Которое тоже должно работать.

И оно работает, но только с помощью dynamic_cast, которое шерстит vtable, а не простым преобразованием типа указателя.

Впрочем, есть ещё RTTI (оператор typeid) для которого даже у класса без виртуальных методов делается ссылка на vTable.

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

В дельфи (и в C Builder) interface — это не класс, это интерфейс COM

Кто вам такое рассказал? В Object Pascal интерфейс играет ту же роль, что и интерфейсы в C# и Java. Это языковое средство.
Синтаксис интерфейсов в C++ Builder соответствует обычному множественному наследованию.

Интерфейсом COM он становится только после прописывания атрибута (GUID) и соответствующей кодогенерации компилятором под конкретную операционную систему.
Ещё есть Delphi под Linux, там тоже есть COM-объекты?
ОДНОВРЕМЕННО оба высказывания не могут быть истинными. ИЛИ одно — ИЛИ другое.

Могут, потому что это зависит от компилятора.

ЕЩЁ РАЗ. Речь о ситуации, когда вы привели объект ко второму базовому классу и передали его в процедуру, которая знает только про второй базовый класс. ЧЕМУ будет равен адрес объекта в этой процедуре?


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

Java, C# и Delphi принципиально разделяют классы и интерфейсы (схема один базовый класс + много интерфейсов). В них указатели на vtable интерфейсов размещаются в основной vtable, поэтому адреса объектов и интерфейсов будут совпадать.

В C++ же классы и интерфейсы не разделяются. Единственный признак — наличие или отсутствие полей, а дальше всё ложится на усмотрение компилятора.

Visual C++ и GCC не будут реализовать класс без полей специальным образом и при любом раскладе заведут второй указатель на vtable в объекте, при этом адреса при использовании подобных «интерфейсов» не будут совпадать.

А вот C++ Builder определяет в процессе компиляции логику работы (класс/интерфейс) и генерит разное размещение для случая классов и интерфейсов. Там адреса объектов совпадут, если используются только интерфейсы.
Я вообще выступаю за то, чтобы неявная конвертация bool <-> int была невозможна, но это поломает кучу старого кода.
Как реализовать сравнение объектов на == и !=???

При множественном наследовании адреса объектов и не будут совпадать — это нормально.
Ну до тех пор, пока не окажется, что на отладочной сборке все хорошо, а на релизной — ИНЫЕ результаты

Обычно это является проявлением ошибок в программе.

Я только один раз сталкивался с действительно багом компилятора — C++ Builder неправильно генерил код для работы с многомерным массивом (писал 4-байтный float в ячейки, а должен был 8-байтный double).

Заменили char objStorage[4096] на что-то вроде double objStorage[512] и все пошло.

И таким образом, вы снова пришли к UB, т.к. выравнивание типов — implementation specific. Вы надеетесь на компилятор, что он выровнит double по размеру типа, что, вообще говоря, он делать не обязан.

Баг это. Неверное описание типа. У части API — void *, в обертках надо правильно писать тип.

Устранение переменной для экономии памяти — это не баг. Полагаться на расположение переменных в памяти — это тоже UB. Я привёл решение по его исправлению, рекомендуемое по стандарту (union).

Ну а кривое API — да, проблема, но к оптимизатору не относится.
Опять ошибка. Передаем указатель на производный объект в процедуру, которой нужен второй базовой класс. И эта процедура — хочет вызвать виртуальный метод. Под каким номером она будет его брать из vTable?

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

Информация

В рейтинге
Не участвует
Откуда
Сербия
Дата рождения
Зарегистрирован
Активность

Специализация

Бэкенд разработчик
Старший