+1
- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
#include <iostream>
template<typename T>
struct CrtpBase {
static float base_func()
{
std::cout << "CrtpBase::base_func(), " << typeid(T).name() << "::int_field == "
<< T::int_field << std::endl;
return 16.0f;
}
static inline float x = base_func();
};
struct A: public CrtpBase<A> {
void func_a()
{
base_func();
}
static inline int int_field = 16;
};
struct B : public CrtpBase<B> {
void func_b()
{
std::cout << "B::func_b(), no CrtpBase<B>::base_func() call" << std::endl;
}
};
int main()
{
A a;
a.func_a();
B b;
b.func_b();
}
[temp.inst]/2:
Unless a class template specialization is a declared specialization,
the class template specialization is implicitly instantiated when
the specialization is referenced in a context that requires a
completely-defined object type or when the completeness of the
class type affects the semantics of the program.
[temp.inst]/3:
The implicit instantiation of a class template specialization causes
(3.1) -- the implicit instantiation of the declarations, but not of the definitions, of
the non-deleted class member functions, member classes, scoped member enumerations,
static data members, member templates, and friends; and
(3.2) -- the implicit instantiation of the definitions of deleted member functions,
unscoped member enumerations, and member anonymous unions.
[temp.inst]/4:
Unless a member of a templated class is a declared specialization, the specialization
of the member is implicitly instantiated when the specialization is referenced in a
context that requires the member definition to exist or if the existence of the definition
of the member affects the semantics of the program; in particular, the initialization
(and any associated side effects) of a static data member does not occur unless the
static data member is itself used in a way that requires the definition of the static
data member to exist.
Таким образом, по стандарту CrtpBase<B>::x не должен быть инициализирован, поскольку он нигде не used in a way that requires the definition of the static data member to exist. Правильные компиляторы (gcc и clang) это понимают и компилируют код, а вот Visual Studio зачем-то пытается инициализировать CrtpBase<B>::x и нон-конформно ломается.
Запостил:
PolinaAksenova,
24 Марта 2021
А в RAII это из коробки:) Но разумеется не бесплатно, а ценой охулиона всяких интересных "вопросиков"
А куда он в "RAII" уходит? Он же в каком-то там деструкторе тоже будет.
delete_group(&grp);
delete_user(&usr);
Рантайм сам последовательно вызовет деструкторы в порядке, обратном вызову констуркторов.
Выше по треду там есть ссылка на вариант без гнутого расширения https://govnokod.ru/24517
А код с гнутыми расширениями — говно по умолчанию, поскольку не соответствует стандарту.
Почему это? Можно такое и на файловый дескриптор типа int навесить, чтоб вызывалось close() по выходу.
.
Должен, но он же просто адрес локалки получает в данном случае. Ну вот как-будто бы ты в сишке позвал cleanup_foo(&f) для какой-то структурки, которая у тебя на стеке валяется (а в ней файловый дескриптор).
так вот жи:
>&f
лол)
Я тоже подумал, что jциферки говорит про вызов деструктора через указатель. А он просто про то, что деструктор должен знать по какому адресу лежит объект, который он собирается уничтожать.
Ну логично
Указатель обязателен для полиморфизма и вирт методов, ну и для работы с кучей само собой.
А без этого можно вообще про указатели ничего не знать кмк
Можно написать и с указателями, и компилятор может соптимизировать так, чтобы реально никаких указателей не было.
Что значит "для каждой новой переменной нужно делать новый блок"?
Х.з., я прагматик -- если стандарт не предлагает красивого и простого решения, то можно и конпеляторозависимой магии наифдефать. Главное более-менее инкапсулировать это, чтобы кишки наружу не торчали. В макрос завернуть хотя бы.
Всё лучше, чем городить хрупкий лес из костылей и тонкостей стандарта.
Общение между программами через расшаренную память (которая тоже системозависимая, да ещё и неоднозначно транслирующаяся, чёрт бы побрал эти CreateFileMapping()+MapViewOfFile()) — это какой-то мазохизм, в обычной прикладухе он не нужен (обычная прикладуха спокойно гоняет данные через локальные сокеты… которые тоже до сих пор не стандартизированы).
Когда-нить и до остального доберутся.
Что значит "рантайм"? Разве для этого нужен какой-то "рантайм" со стороны крестов? Это можно тупо препроцессором каким-то накостылить, что если переменная выходит из скоупа, то вызываем такую-то хуетень.
Нет конечно, это ж не джава какая-нибудь... У меня нет никакого рантайма, а RAII работает. Просто конпелятор сам расставляет вызов деструкторов в точках выхода.
The program can't start because vcruntime140.dll is missing from your computer. Try reinstalling the program to fix this problem.
Ради экономии это делать глупо, да. Но есть и другие причины, например операционка -- это ты сам. Некому сисколлы кидать.
Угу, к примеру вызов 16-битного прерывания через 64-битный интерфейс, переданый по шаред поинтеру.
Кстати, efi через CSM зарботал, спасибо.
Я тут еще вспомнил, что каждая карта должна уметь VGA вообще без всякого VBE, так что сделать универсальный драйвер всё таки можно.
Стандартнаые (не X) режимы позволяют иметь до 640x480 на 16 цветов, а 320x200 даже в 256 (тот самый 13h вроде)
Просто видимо уефи думает, что 320x200 маловато по современным меркам
Не уверен про современные карты.
А по uefi спеке все машины с ним обязаны поддерживать как минимум 800х600 емнип.
То есть гоблины первые у меня не заработают в досе?
Не очень понятно причем тут выпил CRT из винды тогда)
Compiler-support library?
Unwinder?
Аллокатор?
Обёртки над сисколлами?
Всякие memcpy и strcpy?
Крестолибу?
Какие-то важные части запилены, конечно. Если они имеют смысл для не-hosted окружения.
Хотя вот например динамическая память может и не иметь смысла для какой-то мелкой пижни где ты -- единственная прогорамма
ты прав
"Moving to C++ seems wiser than using a dubious hack like this."
Хотя вроде бы можно и отказаться от него
Неймспейсы, миксины можно использовать, RAII есть, switch по строкам еще...
А если "D" настолько охуенен, то почему его никто не использует?
Я просто совершенно однозначно могу сказать, что еще один язык с GC точно не нужен. Их и так охулион и маленькая тележка
А RTTI большинство крестовиков не использует (хочется думать)
Ну и любой dynamic_cast<> — это уже RTTI так-то.
Самому Страуструпу он не очень нравится емнип
"void *" хватит всем.
и тут мы снова возвращаемся к моему любимому
збс
А type_info оно один раз на класс, не на объект. Так что если сильно не метушить и не создавать тысячи типов, то оно не так уж много занимает. Тем более линкер выбросит лишнее, если ты не юзаешь.
Это std::variant получается. Все типы, что у тебя в программе присутствуют, в 8 бит не запихнёшь. А если всю шаблонометушню посчитать, то и в 16 не факт, что уложишься.
256 типов хватит для любого сишника.
Не то сына, не то дочь;
Не мышонка, не лягушку,
А неведому крестушку.
Или даже так: а вдруг Гост это и есть Полина Аксёнова?
Ну так требования к выравненности указателей на разных платформах могут быть раные, и на какой-то платформе если указатель 64-битный но его допустимо выравнивать по 32-битной границе, и свой аналог type_info будем хранить в 32-битах, то массив из такой структуры будет по 32 бита экономить на каждый элемент, в сравнении с двумя обычными указателями
Ну это странная архитектура какая-то... Требует чтения не меньше 32 бит, но при этом кеша нет и от натурального выравнивания 64 бит на 64 профита нету?
и делать связный список из такой фигни
Интересно решение, кстати:)
Когда никакого интернета не было, компьютеры занимали большой машинный зал и программировались через перфоленты-перфокарты, ошибкой это не было. Эксплоиты никого не парили, потому что кто-то просто приходит со своей программой, запускает ее, получает распечатку с результатом выполнения и потом уходит.
Они думают что ты - https://govnokod.ru/user/8086
От слов «пони» и «ня»? :з
Кто ещё использует m dash на говнокоде
Да, крестолиба к сожалению на них намертво завязана. Ты можешь их не юзать, конечно. Но приходится сразу прощаться с векторами и прочими няшными штуками.
Джава вся тоже в исключениях
Но уже в .NET стали завозить всякие "TryParse", то есть уже в 1999-м было понятно, что исключения это не всегда хорошо
ничего, ща вам микропитон завезут в контроллеры, и будут у вас и исключения, и ооп, и всё, что ты любишь
Тут есть кое-какие ньюансы. Если исключения реализуются через механизм setjmp/longjmp хуйни, то от рантайма там только эта setjmp/longjmp хуита нужна, а это вообще из сишного рантайма хрень.
А если механизм исключений реализуется через unwind tables какие-то, см
т.е. в бинарнике есть некое говно https://habr.com/ru/post/208006/ :
> Концептуально, на каждый адрес кода программы хранится информация о том, как попасть в вышестоящий фрейм вызова. На практике ввиду объемности этой информации, она сжимается, фактически, вычисляется с помощью интерпретации байт-кода. Этот байт-код исполняется при возникновении исключения. Расположено всё это в секциях ".eh_frame" и ".eh_frame_hdr".
Да, помимо всего прочего, DWARF интерпретатор представляет собой отличный backdoor, с помощью которого, подменив байт-код, можно перехватить исключение и отправить его на обработку куда душе угодно.
Вот это уже серьезный рантайм.
А в винде тоже есть свое говно с какими Thread Information Block, и о нем в той статье на хабре тоже упоминается.
Еще можно какое-то говно через ретурны сделать теоретически, даже setjmp/longjmp не потребуется, но это пиздец будет, после каждого ретурна проверяем хуйню и если хуйня выставлена то тогда опять ретурним... можно какой-то говнопрепроцессор под это сделать. Считать ли такую дрисню рантаймом?
Тут конечно же надо уточнить, что если надо просто прыгнуть по стекфрейам - это одно дело, а если надо прыгнуть по стекфреймам с вызовом деструкторов для всякого там RAII по дороге - это уже другое. И там уж в стекфрейме надо вспомогательную инфу хранить, типа если бросили исключения, то вот эти деструкторы надо б вызвать по дороге... А что если исключение произойдет в деструкторе когда мы уже обрабатываем исключение? Скорее всего, упадет всё нафиг.
Ну ок, допустим что есть raii-шная обертка над файловым дескриптором, которая в деструкторе делает close(fd). Но close может завершиться с ошибкой:
Предположим, где-то в коде мы успешно открыли файл, начали с ним что-то делать, и тут срабатывает исключение в какой-то фигне, мы раскручиваем стек, надо вызвать close() для файла, но вызвать close не выходит. Ну проверили мы std::uncaught_exceptions(), ну да, раскручиваем стек, и че? Какие дальнейшие действия?
А в сишке?
Или можно сделать exit(EXIT_FAILURE);
Или можно сделать механизм как бы снапшотов через вызовы fork() - ну типа если мы хотим файловый дескриптор открыть, мы перед этим форкаемся, открываем файловый дескриптор в одном из процессов, а в другом самому себе отправляем SIGSTOP и по просыпанию (если оно произойдет) мы типа знаем, что что-то пошло не так. Ну и если где-то какая-то фигня, то тот основной процесс прибивается, и мы продолжаем с того процесса, который до этого спал. И он уже знает что там фигня какая-то, и файл открывать не будет. Но тут всё сложно, ведь если в файловый дескриптор что-то записывалось, то мы эти изменения откатить не сможем т.к. это за пределами нашей компетенции.
Это как? close() вроде нельзя звать второй раз, ошибка из него неисправима.
Ну т.е. два адекватных варианта остаётся:
- заигнорить (можно и в крестах)
- завершить прогу (кидай исключение, кресты сами завершат)
Тут всё не так однозначно
https://stackoverflow.com/a/33114363
> In theory, POSIX was unclear in the past as to whether the fd remains open when close fails with EINTR, and systems disagreed. Since it's important to know the state (otherwise you have either fd leaks or double-close bugs which are extremely dangerous in multithreaded programs), the resolution to Austin Group issue #529 specified the behavior strictly for future versions of POSIX, that EINTR means the fd remains open. This is the right behavior consistent with the definition of EINTR elsewhere, but Linux refuses to accept it. (FWIW there's an easy workaround for this that's possible at the libc syscall wrapper level; see glibc PR #14627.) Fortunately it never arises in practice anyway.
> Per the (amended) standard, on EINTR the fd remains open. However, Linux does not honor this and glibc does not work around the failure to honor it. See the links in my answer. Fortunately EINTR does not happen on close on Linux in any real-world situations I'm aware of, anyway.
Какой багор )))
Заебись. Т.е. если я пишу кроссплатформенный код, мне придётся писать ifdef'ы для каждой операционки, которая возвращает ошибку при EINTR? Ну и забивать на утечку дескрипторов для неизвестных мне ОС.
В очередной раз убеждаюсь, что нехуй вообще было мешать запись и закрытие в один сисколл. Лучше бы всегда в успешной ветке флашить чем пердолиться с ошибками от закрытия... Но теперь это говно уже не исправить, походу.
Именно поэтому я за микроконтроллеры - там этой хуйни вообще нет изначально.
В каких-нибудь либах от вендоров такого говнеца хватает, я думаю. Но их можно не юзать.
Надо еще учесть, что при логгировании может эксепшен сработать.
Да, но тут лучше весь логгер noexcept'ным сделать раз и навсегда. В сишке ведь тоже никто не обрабатывает ошибки от логирующих макросов.
Так и надо, никогда не видел, чтобы у логгера были какие-то ошибки.
Проиницализировал и забыл.
https://habr.com/ru/post/433944/ - да, упадет.
Да кстати нет... Все вот эти if (err) return err весят не сильно меньше. Успешный путь исключения не портят (в нормальном конпеляторе). Да и по фейлу время вполне детерминированное.
А если всю программу хуйнуть в одну функцию и скакать по ней через goto?
Кстати, вот многие сишники плюются от исключений, а сами юзают убогий setjmp.
Но если серьёзно, то похожий подход применяется в sqlite, например: там перед компиляцией все исходники сваливаются в один огромный .c-файл — пишут, что так оптимизация лучше получается на десяток процентов.
днище-то какое
Мемоизация тоже есть (prrecompiled headers), но она вроде только на парсинг, а не на кодогенерецию.
Помнится, я в студии умудрился внутри функции шаблонов наебашить. А потом удивился, что гцц со шлангом так не умеют.
Причём шаблонные классы, шаблонные функции, методы, полностью определённые в определении класса, constexpr-функции, constexpr-статические члены класса и ещё какие-то сущности объявлены inline по умолчанию, и линкер обязан их чистить вилкой без явных указаний программиста.
Т.е. у инлайн функции во всех единицах трансляции один адрес? Хм, не задумывался о такой гарантии.
А всё потому, что код смешали с данными
При этом невиртуальные функции вообще никак не привязаны к данным после конпеляции.
Да, это конечно сложно, но зато это будет охуенно легко скейлиться, можно на куче каких-нибудь распберри-пай какую-то говнину так собирать параллельно, облачную питушню всякую подключать можно.
А так они срут одинаковым говном, которое потом мерджится
> А так они срут одинаковым говном, которое потом мерджится
Сначала проверяем, есть ли там такое говно, потом делаем и срем в бд если нет, а если есть, то берем его, если надо. Можно ж еще как-то умно распределить, какой компилятор какую хуину будет делать, чтобы не было повторов.
Хотя в целом конечно идея не компилировать одно и тоже -- хорошая
Можно коммитить туда, как git какой-нибудь.
Раньше это делали вручную или внешней тулой (кажется у pmake есть команда или даже внешняя, makedepend), потом вроде gcc сам научился.
https://gcc.gnu.org/onlinedocs/gcc/Template-Instantiation.html