LINUX.ORG.RU

Rust и типобезопасность

 ,


3

7

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

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

Почитав документацию:

The as keyword does safe casting

Набросал такой примерчик:

fn main() {
        let a: f64 = std::f64::MAX;  // данное значение просто пример "большого числа"
        let b = a as i64;
        println!("{}", b);
}

Вопросы:

1) С какой стати это вообще компилируется?

2) Да, f64 и i64 нужно одно и то же количество битов для хранения значения, ну и что?

3) Почему результат меняет знак?

Представьте, что какой-то тех. процесс идет, и определенный параметр нельзя изменять скачкообразно, иначе физически система (по крайней мере, один из компонентов) выйдет из строя (встанет в раскоряку, взорвется, выпустит токсичный газ, убивающий 100тыс. населения; нужное подчеркнуть). И вот значение в f64 положительное и увеличивается постепенно, с i64 все вроде в порядке (и тестирование проходит на тестовых значениях), и вдруг хренак! и уже -9223372036854775808

Как так?

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

Ты дурачка-то не включай. Нормальное ООП начинается с инкапсуляции. Если ты инкапсуляцию ломаешь, чтоб пропатчить метод, то ООП у тебя отсутствует по определению.

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

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

Можно заранее все сливы засчитывать.

Да этому горе-демагогу можно было защитать слив уже за одно вот это в контексте разговора про С++:

Добавив сюда параметры по умолчанию, получили полную жопу и теперь вынуждены писать имена параметров Something(capacity: 100)

У него, видимо, какой-то свой собственный C++, с именованными параметрами.

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

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

быть не может

Вы не поверите.

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

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

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

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

Зачем тащить в новый язык старые ошибки? self нужен чтобы не извращаться с m_* и прочим ужасом.

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

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

При чём тут лайфтаймы? Или вы про аргумент функции? Ну тут раст тоже удобнее, так как сразу ясно что функция делает и не нужно лезть в хедер и проверять помечена она как static или нет. Explicit is better than implicit.

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

Или вы про аргумент функции?

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

Ну тут раст тоже удобнее, так как сразу ясно что функция делает и не нужно лезть в хедер и проверять помечена она как static или нет. Explicit is better than implicit.

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

П.С. если что, мне нравятся трейты

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

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

С классами тоже самое. Ну и подход раста, это - данные отдельно, интерфейс отдельно. Тут бессмысленно обсуждать критерий удобства и правильности. Это просто другой подход. И наевшись проблем с ООП в C++ я только рад такому подходу.

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

С классами тоже самое.

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

подход раста, это - данные отдельно, интерфейс отдельно. Тут бессмысленно обсуждать критерий удобства и правильности.

Это разделение не отменяет наличие impl у структуры. Условно говоря, никто не мешает разделить класс на данные и методы, но при этом не разрывать его на мелкие части.

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

Мы или ищем все трейты которые реализованы для типа (cargo doc в помощь) или руками проходим по всем дочерним классам. Разницы никакой.

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

Он-то тут при чём?

Это разделение не отменяет наличие impl у структуры.

И? В C++ я не могу добавить метод к структуре без её модификации или наследования. В расте могу.

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

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

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

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

наследование, это не «наследование реализации». наследование это СПЕЦИАЛИЗАЦИЯ имеющейся реализации. Я пишу свой класс - «некрашеный автомобиль» и даю его вам. вы можете из него одним движением сделать класс - крашеный автомобиль, и отдать его тому - кто эти автомобили «продает» клиенту.

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

у вас 200 штук классов, и допустим скрытых свойств не одно, а 10, чтоб жизнь медом не казалась. в плюсах это будет 10 функций на всю систему, скрытых внутри каких-то файлов, которые не видны прикладнику.

а в расте это обудет 2000(!) функций написанных ручками, о которых знают все, и все знают, что они быть должны, и даже знают, как их реализовать… вы уверены, что в расте есть инкапсуляция??? как реально сокрыть это все??? вот. без наследования нет реальной инкапсуляции.

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

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

Мы или ищем все трейты которые реализованы для типа (cargo doc в помощь) или руками проходим по всем дочерним классам. Разницы никакой.

Вообще никакой, хорошо.

Он-то тут при чём? И? В C++ я не могу

Он-то тут при чём? (c)

добавить метод к структуре без её модификации или наследования

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

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

И? В C++ я не могу добавить метод к структуре без её модификации или наследования. В расте могу.

можешь :). напиши например void ff(Struct &self, …). или ты не понял, что раст пишет это же самое??? в расте методы не привязаны к структуре на самом деле. они не инкапсулированы в ней(что нарушает как раз инкапсуляцию), они инкапсулированы в модуле. но модули - это не ооп. чтобы понять какие-же методы имеет данный растовый «псевдокласс», надо перелопатить весь код либо поиском, либо тулзой, что будет из кода вытаскиваться методы классов.

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

Очень остроумно. Ждём Uniform Function Call Syntax. А пока что это треш, ибо даже chaining не сделать.

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

а в расте ВСЕ методы так реализованы! это вполне себе традиционные байндинги, которые вирт еще в оберон воткнул. идея - структура + раскиданные по модулю байндинги - это еще от оберона идет. можете удостовериться. но вирт был сторонник КОМПОНЕНТНОГО программирования, как некоего концепта, и потому не особо заморачивался с ООП.

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

Вам никто не мешает сделать приватный трейт со стандартной реализацией.

пример приведите, и не кидайтесь какашками постмодернистских терминов… я даже не знаю что такое приватный трейт!

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

более того! в русте в трейтах же есть реализация метода по умолчанию

А еще в rust зарезервированы ключевые слова final и override. Посмотрим, выстрелит ли это ружье.

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

А еще в rust зарезервированы ключевые слова final и override. Посмотрим, выстрелит ли это ружье.

:)))) чуваки решили соломку таки подстелить.

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

потому что приватные методы, видимые в хидере - это противоречит инкапсуляции.

Шта? Инкапсуляция - это про область видимости/доступности (хз как правильно называется) типа компилятору. То что программист может прочесть сорцы - это не инкапсуляция.

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

пример приведите

Задачу сформулируйте конкретно, а то опять вилять начнёте.

постмодернистских терминов

private и в плюсах есть, алё.

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

Там и try/catch есть. Дальше что?

И не просто есть, а и недавно добавлены. Но, если ты к тому, что try/catch не про исключения, то final/override таки подвязаны к предложению об наследовании реализации.

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

Да этому горе-демагогу

Мы так-то уже определили демагога, который перевирал слова оппонентов, а потом их «опровергал».

можно было защитать слив уже за одно вот это в контексте разговора про С++:

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

Я никогда не утверждал, что такое можно в C++. В контексте ненужности перегрузки я рассказал про проблемы этой фичи. Такое можно в C#, в котором есть перегрузка и параметры по умолчанию. И такое, если повезёт, появится в C++ 2030. Потому что иначе с дефолтными параметрами тяжко, второй параметр с дефолтным значением уже становится труднодоступным.

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

Дай ссылку на это и я признаю, что не прав во всем, и что Rust идеален.

лови: Rust и типобезопасность (комментарий)

Теперь самое время начинать мазаться, что ты вовсе не то имел в виду, когда показывал этот говнокод, что это вовсе не демонстрация супермегафичи, которую не умеет Раст :).

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

ТЫ, лично ты обещал возможность сохранить шаблон в переменную

лови: Rust и типобезопасность (комментарий)

ловите_наркомана.jpeg

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

Потому что иначе с дефолтными параметрами тяжко второй параметр

с дефолтным значением уже становится труднодоступным.

foo(,2)
foo(_,2)

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

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

это не просто лишние 10 «строк кода». это сотни-тыщи строк лишнего кода в виде текста на языке чудесатого програмирования,

Согласен, расту сильно не помешает макрос типа [redirect(SomeTrait, privateField, method1, method2, method3…)] Чисто для сумасшедших фанатов наследования. Такой подход всё равно лучше, так как позволяет обращается только к публичным методам и явно перечисляет методы, которые должны быть наследованы, так что при добавлении чего-то в трейт или при имплементации базовым классом новых трейтов оно автоматически «наследованному» не передастся.

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

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

наследование, это не «наследование реализации». наследование это СПЕЦИАЛИЗАЦИЯ имеющейся реализации. Я пишу свой класс - «некрашеный автомобиль» и даю его вам. вы можете из него одним движением сделать класс - крашеный автомобиль, и отдать его тому - кто эти автомобили «продает» клиенту.

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

у вас 200 штук классов, и допустим скрытых свойств не одно, а 10, чтоб жизнь медом не казалась. в плюсах это будет 10 функций на всю систему, скрытых внутри каких-то файлов, которые не видны прикладнику.

Если у вас 200 классов, то вам наследование мало поможет. Макросы в помощь. В плюсах, кстати, тоже так делается, см

class Foo : public QObject
{
    Q_OBJECT // а это что такое?
...
}

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

Чего? Инкапсуляция на месте, причём не ущербная, так как нет наследования. Полиморфизм на месте. Нет только наследования.

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

ловите_наркомана.jpeg

слив засчитан. Вот на что ты вообще надеялся, интересно?

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

Шта? Инкапсуляция - это про область видимости/доступности (хз как правильно называется) типа компилятору. То что программист может прочесть сорцы - это не инкапсуляция.

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

то что я сказал, имеет смысл только если:

  • класс публичный, и неохота показывать его приватные методы(что нормально).
  • для непубличного класса, локального в единице компиляции то, что я сказал - ИЗЛИШНЕ, там проще использовать приватные методы, и не париться.

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

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

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

Если у вас 200 классов, то вам наследование мало поможет. Макросы в помощь. В плюсах, кстати, тоже так делается, см…

макросы там совершенно не причем.

class Atom{ public: string &name(){…} string &guid(){…} }

class C :public Atom{ } class CC :public C{} class CCC:public CC{} .. и так до бесконечности..

все классы имеют свойства name и guid, причем реализованные внутри Atom, и вызываемые СТАТИЧЕСКИ. то есть адрес рассчитывается на этапе линковки, и корректируется загрузчиком если надо. никаких виртуальных таблиц, необходимых для трейтов.

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

Сами придумали какую-то ерунду - сами её и опровергли.

в расте кстати можно добавить метод к структуре не внутри того модуля где она определена?

Да.

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

final/override таки подвязаны к предложению об наследовании реализации

Пруфца бы.

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

Вам уже 10 раз объяснили, что у трейтов нет vtable.

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

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

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

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

да чо там! читаем https://doc.rust-lang.org/1.29.2/book/first-edition/trait-objects.html#representation, там все написано:

The methods of the trait can be called on a trait object via a special record of function pointers traditionally called a ‘vtable’ (created and managed by the compiler).

A vtable is essentially a struct of function pointers, pointing to the concrete piece of machine code for each method in the implementation. A method call like trait_object.method() will retrieve the correct pointer out of the vtable and then do a dynamic call of it.

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 2)
Ответ на: комментарий от khrundel

Кстати, читал недавно предложение запилить в плюсы нормальную кодогенерацию, чтоб можно было библиотекой qobject реализовать, без вызова внешней moc, или interface…

Я не в курсе что ты там читал. Но есть проект https://www.copperspice.com/ где отвезали поганый Qt от moc.

Сейчас требуют С++17 компилятор, но первая версия которая отвязана от moc требовала лишь C++11

А вот эти ребята назад бекпортировали эти отвязания для оригинального Qt: https://github.com/woboq/verdigris

И требуют С++14 компилятора. Кстати всем рекомендую, можно пользоваться Qt как обычной либой хоть в обычном Makefile и не париться с лишними шагами кодогенерации с moc.

Так что qobject реализовать без moc можно было с С++11…

Meta-Object Compiler (moc)

The Meta-Object Compiler is no longer required for generating reflection meta data in CopperSpice

Since moc is no longer required it was completely removed

All functionality originally provided by moc was replaced with compile time templates

CopperSpice automatically generates meta data for processing Signals/Slots and Introspection

A template class can now inherit from QObject with no restrictions on data types

Complex data types can be used as a signal or slot argument, for example this is valid in CopperSpice: QMap<QString, int>

Removal of moc simplifies the build process

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

Trait != TraitObject. В отличии от С++, vtable не зашивается в структуру. Посмотри на реализацию твоего примера на Rust

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

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

Посмотри на реализацию твоего примера на Rust

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

class Atom{ 
public:
  string &name(){…} 
  string &guid(){…} 
};
class C1:public Atom{ };
class C2:public C1{ };
class C3:public C2{ };
class C4:public C3{ };

вот тут в 9 строках обьявлены 5 классов, и у всех пяти есть методы name, guid. что нам предлагает руст вместо такой записи?

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

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

Именно это я и имел виду.

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

Нет, читай ссылку которую ты привёл выше, там всё разжёвано.

fn main() {
    let c = C(AtomData::new("C", "C_GUID"));
    let cc = CC(C(AtomData::new("CC", "CC_GUID")));
    
    dump_static(&c);
    dump_static(&cc);
    
    dump_dynamic(&c);
    dump_dynamic(&cc);
    
    use std::mem::size_of;
    println!("size_of String = {}", size_of::<String>());
    println!("size_of AtomData = {}", size_of::<AtomData>());
    println!("size_of C = {}", size_of::<C>());
    println!("size_of CC = {}", size_of::<CC>());
}
 static: name = "C", guid = "C_GUID"
 static: name = "CC", guid = "CC_GUID"
dynamic: name = "C", guid = "C_GUID"
dynamic: name = "CC", guid = "CC_GUID"
size_of String = 24
size_of AtomData = 48
size_of C = 48
size_of CC = 48

Как видишь в структуру ничего не вшито.

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

Ты показывай полную реализацию, и я покажу.

using namespace std;
class Atom{ 
	static int _count; //статическмй счетчик
	string _name;
	int _guid;
	
public:
	Atom():_guid(++_count){ }
	const string &name()const {return _name;}
	int guid() const{return _guid;} 
	void setName(const string &fs){_name=fs;}
};
int Atom::_count=0; //

class C1:public Atom{};
class C2:public C1{};
class C3:public C2{};
class C4:public C3{};
alysnix ★★★
()
Ответ на: комментарий от numas13

Как видишь в структуру ничего не вшито.

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

let c = C(AtomData::new("C", "C_GUID"));    
let cc = CC(C(AtomData::new("CC", "CC_GUID")));

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

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

Atom():_guid(++_count){ } - undefined behavior при создании экземпляров классов в разных потоках. Нужно использовать std::atomic<int>. Undefined behavior при переполнении _count (до C++ 20, кажется). Нужно использовать std::atomic<unsigned int>.

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

Atom():_guid(++_count){ } - undefined behavior при создании экземпляров классов в разных потоках.

не мути воду. мы пока потоков не касались вообще. это модельный пример на ооп нотацию.

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

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

Если как было записано изначально, то вообще не будет вызван ни dump_static ни dump_dynamic, всё будет заинлайнено в main.

https://gcc.godbolt.org/z/PohadF

Если поставить #[inline(never)]

https://gcc.godbolt.org/z/RbaMya

и посмотреть на строки 158 и 187

То как я понимаю в dump_static будет заинлайнено: c.name() и c.guid()

А в dump_dynamic будут вызваны функции c.name() и c.guid() через vtable.

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

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

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