Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.77/47: Рейтинг темы: голосов - 47, средняя оценка - 4.77
901 / 478 / 93
Регистрация: 10.06.2014
Сообщений: 2,700

Почему деструктор срабатывает больше раз, чем количество созданных объектов?

18.01.2017, 16:35. Показов 10190. Ответов 111
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Вопрос в заголовке темы. Почему? Создается всего 2 объекта, но деструктор вызывается трижды.
Вот пример
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
#include <vector>
 
class Foo
{
    public:
    Foo(int n)
    {
        std::cout << "CONSTRUCT" << std::endl;
    }
    ~Foo()
    {
        std::cout << "DESTRUCTED" << std::endl;
    }
};
 
int main()
{
    std::vector<Foo> v;
    v.reserve(2);
    v.emplace(v.begin(), 1);
    v.emplace(v.begin(), 2);
    std::cout << std::endl << v.capacity() << std::endl;//2
}
http://rextester.com/CFBZ76666

Ещё интересует вот что. Если описать деструктор, нужно ли описывать ещё и деструктор по умолчанию? Если нет, то каким образом происходит освобождение памяти, которое было занято для объекта (речь о простых типах)
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
18.01.2017, 16:35
Ответы с готовыми решениями:

Можно ли обеспечить взаимодействие программно созданных объектов и объектов, созданных мастером
Здравствуйте. Изучаю C# и ADO.NET и столкнулся с одной серьезной проблемой, которая мешает комфортно программировать. Часто...

Почему не срабатывает деструктор и стоимость продуктов не выводится в формате действительного числа?
Добрый вечер. Помогите пожалуйста решить проблему: /*Программа демонстрирует механизм работы конструкторов, деструктора, дружественных...

Почему у двух созданных объектов одинаковые имена
Почему когда я создал 2 объекта и дал им разные имена, в итоге получается что у этих двух объектов одно имя? package helloworld; import...

111
2784 / 1937 / 570
Регистрация: 05.06.2014
Сообщений: 5,602
22.01.2017, 20:40
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от ct0r Посмотреть сообщение
WAT? terminate вызывает abort, abort шлет SIGABRT, а что делается при принятии SIGABRT можно посмотреть в man 7 signal. (Подсказка: при выполнении программы появляется строка "Aborted (core dumped)".)
Добро пожаловать в удивительный мир Windows - " The default SIGABRT action is for the calling process to terminate with exit code 3, returning control to the calling process or operating system."
Стандарт дампа не гарантирует, так что рассчитывать мы можем только на аварийное завершение процесса и ничего больше.
Цитата Сообщение от ct0r Посмотреть сообщение
Почему 100? Даже в случае вызова внутри только тех функций, которые noexcept?
Потому что механизм статической линковки очень туп и прицепляет к программе половину заранее скомпилированных STL библиотек. В Вижуал Студии вроде как наконец это безобразие поправили, а вот Mingw по-прежнему радует Hello World! на полмегабайта. Или внезапным раздуванием программы вообще не использующей STL явно, но подключающей ее косвенно через noexcept конструктор.
0
 Аватар для Fulcrum_013
2083 / 1574 / 169
Регистрация: 14.12.2014
Сообщений: 13,614
22.01.2017, 22:30
Цитата Сообщение от Renji Посмотреть сообщение
Ну так он их и имеет, "catch секция" называется.
.правильно. Но кто то кого вызыают внутри этой секции должен исключения кидать в случае чего (например при копировании или добавлении стринга память не выделилась)
Цитата Сообщение от Renji Посмотреть сообщение
Добавить в класс единственный std::string.
Вообще то по задумке конструктор перемещения должен не распределять чего то а просто перемещать указатели. т.е суть - при реаллоке не распределение новых буферов живущих к примеру в каждом элементе вектора, не копирование в них данных из старых а потом уничтожение старых при реаллокации а просто перенос указателей на уже существующие буфера в новое место

Добавлено через 9 минут
Цитата Сообщение от Renji Посмотреть сообщение
В Вижуал Студии вроде как наконец это безобразие поправили,
В вижуал студи со статической линковкой без STL хелловверд получается в районе полутора метров. Ну правда винапи малехо тянет. То ли у них формат библиотек у майкрософта не правильный то ли черт его разберет. Но для сравнения борландовский линкер еще в середине 90-ых умел вырезать только те функции которые реально вызываются.
Кстати сама STL практически полностью инлайнится
0
2784 / 1937 / 570
Регистрация: 05.06.2014
Сообщений: 5,602
22.01.2017, 22:47
Цитата Сообщение от Fulcrum_013 Посмотреть сообщение
.правильно. Но кто то кого вызыают внутри этой секции должен исключения кидать в случае чего (например при копировании или добавлении стринга память не выделилась)
Так и в чем проблема? Написали throw; в конце catch-секции и исключение дальше полетит. Именно то, которое мы поймали.
Цитата Сообщение от Fulcrum_013 Посмотреть сообщение
Вообще то по задумке конструктор перемещения должен не распределять чего то а просто перемещать указатели.
Он еще должен оставлять исходный объект в корректном состоянии. То есть, если в этом объекте есть стринг, в этот стринг надо хоть что-то положить. Хотя-бы пустую строчку-заглушку. Ну а если даже заглушка может плюнуться исключением, то опаньки...
Цитата Сообщение от Fulcrum_013 Посмотреть сообщение
В вижуал студи со статической линковкой без STL хелловверд получается в районе полутора метров.
2015 Студия, RTL выставлен в Multithreaded (вместо Multithreaded DLL). Одна строчка std::cout << "Hello world!" << std::endl; дает исполняемый файл на 176 кило. Пустой main - 73 кило. Хотелось бы конечно еще меньше, но хоть не пол мегабайта как у Mingw.
0
Игогошка!
 Аватар для ct0r
1801 / 708 / 44
Регистрация: 19.08.2012
Сообщений: 1,367
22.01.2017, 22:51
Цитата Сообщение от Renji Посмотреть сообщение
Добро пожаловать в удивительный мир Windows
Ну это ж винда! Там надо либо свой хэндлер на аборт делать, либо руками через менеджер задач дамп создавать, когда сообщение об аборте вылетит. Может еще как можно, я в винде нуб. В любом случае, возможность получить дамп есть.

Цитата Сообщение от Renji Посмотреть сообщение
рассчитывать мы можем только на аварийное завершение процесса и ничего больше.
Что уже лучше, чем UB.
0
 Аватар для Fulcrum_013
2083 / 1574 / 169
Регистрация: 14.12.2014
Сообщений: 13,614
23.01.2017, 00:40
Цитата Сообщение от Renji Посмотреть сообщение
То есть, если в этом объекте есть стринг, в этот стринг надо хоть что-то положить. Хотя-бы пустую строчку-заглушку. Ну а если даже заглушка может плюнуться исключением, то опаньки...
Во первых по задумке ничего нового ложить туда не надо. надо переложить из старого в новый а старый обнулиить. Опять же если это стринг то заглушка если через нее реализована может быть и статической. спокойно себе жить статик мембером и на нее указываться при обнулении. Хотя обычно просто нулят. т.к. обычно стараются сделать строку аналогом char* хотя и с copy-on-change symantic.

Добавлено через 41 минуту
Цитата Сообщение от Renji Посмотреть сообщение
дна строчка std::cout << "Hello world!" << std::endl; дает исполняемый файл на 176 кило. Пустой main - 73 кило
А инициализация класса окна и самого окна тянут уже на 1,5мб в релизе. Пр этом небольшой 3D космошутер на DX9 с динамической RTL в дебаге 200kb. Она похоже просто RTL DLL-ки целяком впаковывает с альтернативными точками входа а потом из себя их загружает. При этом DLL не static lib их на куски резать категорически нельзя.
0
2784 / 1937 / 570
Регистрация: 05.06.2014
Сообщений: 5,602
23.01.2017, 00:55
Цитата Сообщение от ct0r Посмотреть сообщение
Ну это ж винда! Там надо либо свой хэндлер на аборт делать, либо руками через менеджер задач дамп создавать, когда сообщение об аборте вылетит.
Ну окей, создали дамп, просмотрели откуда вызван std::abort. "Виновником" сбоя оказалась строчка throw; в catch секции. Сильно помогло?
Цитата Сообщение от ct0r Посмотреть сообщение
Что уже лучше, чем UB.
Хуже. Во-первых, если я захочу чтобы мне навязывали механизмы защиты от дурака работающие на стадии исполнения программы, я пойду в те языки, где каждый operator[] принудительно проверяет выход за границы массива.
Во-вторых, при наличии какого-либо межпроцессного взаимодействия, UB будет все равно. Например, в коде dll, по понятным причинам вообще не использующей механизма исключений (но использующей noexcept деструкторы).
Цитата Сообщение от Fulcrum_013 Посмотреть сообщение
Во первых по задумке ничего нового ложить туда не надо. надо переложить из старого в новый а старый обнулиить.
Чтобы из старого в новый что-то положить, надо сначала в старом чего-то создать. А у нас, напоминаю, разговор про конструктор. На момент его вызова в старом объекте еще ничего не создано. Вот, собственно, и получаем сценарий "создать пустой объект и swap-нуть его с перемещаемым", который падает на стадии "создать пустой объект".
0
 Аватар для Fulcrum_013
2083 / 1574 / 169
Регистрация: 14.12.2014
Сообщений: 13,614
23.01.2017, 01:30
Цитата Сообщение от Renji Посмотреть сообщение
На момент его вызова в старом объекте еще ничего не создано. Вот, собственно, и получаем сценарий "создать пустой объект
Если объект который нам дали живет пустой то это означает что он спокойно может существовать пустым. И наша задача ничего не выдумывать а спокойно скопировать пустышку. А вот если он не может существовать пустым то не в конструкторе копирования нужно лисапедить а в других конструкторах ошибку исправлять.

Добавлено через 18 минут
Цитата Сообщение от Renji Посмотреть сообщение
где каждый operator[] принудительно проверяет выход за границы массива.
Rстати поезнейшая штука при отладке. У меня все что operator[] или свойства-массивы имеет так в дебаге и живет и исключения чуть что кидают. В IDE cразу по стеку вызовов видно откуда лажевый индекс пришел. А в релизе все это выпиливается.

Добавлено через 7 минут
Цитата Сообщение от Renji Посмотреть сообщение
о-вторых, при наличии какого-либо межпроцессного взаимодействия, UB будет все равно.
В реалиях некоторых осей даже аварийный креш это не конец а только начало. Потому как данные (во всяком случае какая то часть) при этом никуда не деваются и пока тебя аварийно перезапускают другие процессы продолжают их использовать. Поэтому дабы ничего не взорвалось никаких UB в этих данных быть не должно в принципе как бы не вылетел. А после перезапуска первым делом разобрать что там в них прямое а что не очень.
Хотя в реалиях таких задач и реалоки и временные буфера считаются дурным тоном. Дабы память не фрагментировать все выделяется на старте с резервом и живет до сбоя электропитания (ну или креша что не хорошо). Так же как и контейнеры там обычно не разу не STL-кие. Наиболе часто пользуемый - кольцевой буффер.
0
2784 / 1937 / 570
Регистрация: 05.06.2014
Сообщений: 5,602
23.01.2017, 02:43
Цитата Сообщение от Fulcrum_013 Посмотреть сообщение
Если объект который нам дали живет пустой то это означает что он спокойно может существовать пустым. И наша задача ничего не выдумывать а спокойно скопировать пустышку.
Так я же говорю - там лежит std::string, у которого даже строка-пустышка исключениями плеваться может.
C++
1
2
3
4
5
6
7
8
9
10
11
12
class MyClass
{
public:
    //Конструктор перемещения неявно вызывает конструктор str
    //А конструктор str может кинуть исключение, потому что noexcept ему дали только в C++17
    MyClass(MyClass&&src){
        std::swap(str,src.str);
    }
 
private:
    std::string str;
};
Цитата Сообщение от Fulcrum_013 Посмотреть сообщение
Rстати поезнейшая штука при отладке.
Именно при отладке. А при релизе - уж давайте с предварительного согласия программиста, а не в добровольно-принудительном порядке.
Цитата Сообщение от Fulcrum_013 Посмотреть сообщение
Поэтому дабы ничего не взорвалось никаких UB в этих данных быть не должно в принципе как бы не вылетел.
А в noexcept функции не должно быть throw ни под каким соусом. Но мы же рассматриваем случай идиота пишущего throw сразу под noexcept. Значит, должны рассмотреть и случай куда меньшего идиота, накосячившего в межпроцессном взаимодействии.
0
 Аватар для Fulcrum_013
2083 / 1574 / 169
Регистрация: 14.12.2014
Сообщений: 13,614
23.01.2017, 03:45
Цитата Сообщение от Renji Посмотреть сообщение
Так я же говорю - там лежит std::string, у которого даже строка-пустышка исключениями плеваться может.
Ну а просто ее переместить никак? Тупо как char*? У нормальных строк под капотом только указатель на буфер и больше ничего. конструктор перемещения он для того и придуман чтобы никаких конструкторов не трогать в отличии от конструктора копирования. Да и вообще строки свои иметь надо потому как std::string недопиленный глючный лисапед.
Который ни вот так не умеет
C++
1
2
    String a;
    a = String("Value:")+"["+5.5+"]";
ни вот это нормально не обрабатывает:
C++
1
   a[5]=0;
А борландовские строки только с борландовским менеджером памяти дружат, который им между борландом компиленными dll ходить помогает без интерфейсов и прочих пенальти.
Так что добро пожаловать в удивительный мир NonVisual Studio где для нормальной работы строки, массивы. списки указателей, владеющие контейнеры, мультисписки обработки, деревья и двунаправленные указатели и все остальное свои must have для серьезных дел.
Цитата Сообщение от Renji Посмотреть сообщение
Именно при отладке. А при релизе - уж давайте с предварительного согласия программиста, а не в добровольно-принудительном порядке.
Еще раз говорю - свое иметь надо а не всякими глупостями с забора пользоваться. Оно свое и работает как надо и экскепшнами кидается когда хочешь. А если совместимости хотят то стандартизировать нужно форматы данных, а не методы их обработки причем так что нигде пользовать невозможно. И сам язык развивать а не библиотеку о конечном назначении которой и соответсвенно архитектуре они не могут сказать ничего определенного по определению.
Цитата Сообщение от Renji Посмотреть сообщение
Значит, должны рассмотреть и случай куда меньшего идиота, накосячившего в межпроцессном взаимодействии.
Ну такие косяки обычно вылазят задолго до того как оно на реальное оборудование ставить. Скорее всего при первом же дебаг-запуске и будет происходить стабильно. А что касается именно конструкторов перемещения - то его назначение обеспечить векторам смартпоинтеров при реаллоке такую же эффективность как и динамическим массивам сырых указателей. Соответственно единственный способ в конструкторе перемещения косяков не допустить - тупо все копировать а у старого нулить не пользуясь никакими примочками конструкторами и т.п. А еще лучше массивы сырых указаетлей пользовать вместо всяких подкапотных распределений копирований и т.п. Т.е. вместо vector<shared_ptr> массив где каждый указатель сырой а сам массив умный (в том числе владеющий или слабо владеющий) а то и массив двусторонних указателей хотя во многих случаях это избыточно . Кстати вся беда с двусторонней концепцией указателей именно в этом - какая часть двустороннего функционала нужна а какая избыточна угадать в общем невозможно, можно только в каждом конкретном случае определить. А память кушают зело. При константной по времени обработке связки/развязки примерно раз в 5 оверхед по памяти под указатель. Вернее до 5 раз. чем больше ссылок тем оверхед к 3 стремится. И если к примеру в GUI это нормально то к примеру если дверь имеет 2 петли и две ручки иметь такие указатели на нее слишком если моделируемый мегаполис Москва (тут вообще двери отдельным объектом жить жалко не то что петлям и ручкам да еще и с двунаправленными указателями )
0
Игогошка!
 Аватар для ct0r
1801 / 708 / 44
Регистрация: 19.08.2012
Сообщений: 1,367
23.01.2017, 04:10
Цитата Сообщение от Renji Посмотреть сообщение
Сильно помогло?
Да, бэктрейс и все такое сильно помогает, внезапно Может любителям UB оно и не надо, они просто по фану стараются начать искать проблему как можно дальше от места ее возникновения, чтобы преодолеть кучу трудностей, испытать всякие озарения и все такое

Цитата Сообщение от Renji Посмотреть сообщение
работающие на стадии исполнения программы
Раньше были претензии к размеру кода (хотя казалось бы, компилируй без исключений, если они вообще не нужны, и дело в шляпе). А теперь что-то работает на стадии исполнения. Что именно-то? Гигантский try кушает все ядро?

Цитата Сообщение от Renji Посмотреть сообщение
Например, в коде dll, по понятным причинам вообще не использующей механизма исключений (но использующей noexcept деструкторы).
Я пишу шаред либы со всеми плюшками, а снаружи просто выкладываю сишку, что не так? Если не хочешь поддержки исключений в принципе - выруби флагом компилятора, в чем проблема?

Цитата Сообщение от Renji Посмотреть сообщение
Но мы же рассматриваем случай идиота пишущего throw сразу под noexcept.
Как раз имеется в виду уже большая система, в которой уже никто не знает (не помнит), где, кто, и на какой фиг ставил noexcept.
0
2784 / 1937 / 570
Регистрация: 05.06.2014
Сообщений: 5,602
23.01.2017, 14:05
Цитата Сообщение от ct0r Посмотреть сообщение
Да, бэктрейс и все такое сильно помогает, внезапно Может любителям UB оно и не надо, они просто по фану стараются начать искать проблему как можно дальше от места ее возникновения, чтобы преодолеть кучу трудностей, испытать всякие озарения и все такое
Любителям UB надо чтобы снимок стека вызовов делался в момент возникновения ошибки, а не в момент переброски исключения впечатавшегося в noexcept функцию. И чтоб в конструктор исключения автоматически передавали __FILE__ и __LINE__. Но такой функционал надо велосипедить.

А ваш (полу)стандартный бектрейс, повторюсь, приведет вас только к строчке throw;, которая не имеет никакого отношения к причинам возникновения ошибки. Это просто переброска исключения, которое в совсем другом файле возникло.
Цитата Сообщение от ct0r Посмотреть сообщение
Раньше были претензии к размеру кода (хотя казалось бы, компилируй без исключений, если они вообще не нужны, и дело в шляпе). А теперь что-то работает на стадии исполнения. Что именно-то? Гигантский try кушает все ядро?
Гигантский try ожидающий несуществующего исключения, кушает половину файла. А компиляция без исключений да, проблему решает, но не стандартизирована. Если строго по стандарту, деструктор должен ловить все исключения (потому что автоматически noexcept) и все тут. Даже если этих исключений в программе нет как класса.
Цитата Сообщение от ct0r Посмотреть сообщение
Я пишу шаред либы со всеми плюшками, а снаружи просто выкладываю сишку, что не так?
Не так то что эта сишка не должна плеваться исключениями, а значит, должна преобразовывать их в сишные коды ошибок. Причем, преобразование придется делать в каждой экспортируемой функции и исключительно ручками. Noexcept модификатор то такого фокуса не умеет. Что и является поводом переделать код в сторону отказа от исключений. Хотя да, отказ от исключений не всегда будет более простым выходом чем преобразование исключений в сишные коды.
Цитата Сообщение от ct0r Посмотреть сообщение
Как раз имеется в виду уже большая система, в которой уже никто не знает (не помнит), где, кто, и на какой фиг ставил noexcept.
Документацию надо поддерживать, тогда и будет известно кто, где ставил noexcept.
0
 Аватар для Fulcrum_013
2083 / 1574 / 169
Регистрация: 14.12.2014
Сообщений: 13,614
23.01.2017, 22:03
Цитата Сообщение от Renji Посмотреть сообщение
Гигантский try ожидающий несуществующего исключения, кушает половину файла. А компиляция без исключений да, проблему решает, но не стандартизирована. Если строго по стандарту, деструктор должен ловить все исключения (потому что автоматически noexcept) и все тут. Даже если этих исключений в программе нет как класса.
При этом самая удобная схема - блок try-catch в мэйне внутри которого создание главного объекта иерархии и его запуск. При этом внутри методов классов (в том числе деструкторах и т.д.) ловятся исключения только те которые явлдяются сообщениями об ошибках внешних компонентов и возникновение которые нельзя предотвратить внутри программы и можно обработать на месте. (например нет подключения к БД не открылся сокет и тп). То что нельзя не предотваратить не обработать - остается только показать пользователю что у него что то не так (ну типа пусть сначала WiFi включит а потом связь по сети заказывает). Из оставшегося -. то что можем обработать ловим, то что нет - фактически признак некорректной логики программы. Соответсвенно ловим их дебаггером и фиксим баги которые привели к их возникновению.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
23.01.2017, 22:03
Помогаю со студенческими работами здесь

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

Монета брошена 800 раз. Найти вероятность того, что «герб» выпадет на 20 раз больше, чем решка
Решите пожалуйста)

Используя статическую компоненту класса подсчитать количество созданных в программе объектов
Задание: Используя статическую компоненту класса подсчитать количество созданных в программе объектов. Статическую компоненту класса я...

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

Почему таймер срабатывает несколько раз?
Доброго времени суток, друзья. Нужен таймер, по прошествии которого выполняется программа. Создаю таймер: Timer time = new Timer(); ...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
112
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Обработчик клика мыши в браузере ПК и касания экрана в браузере на мобильном устройстве
8Observer8 02.02.2026
Содержание блога Для начала пошагово создадим рабочий пример для подготовки к экспериментам в браузере ПК и в браузере мобильного устройства. Потом напишем обработчик клика мыши и обработчик. . .
Философия технологии
iceja 01.02.2026
На мой взгляд у человека в технических проектах остается роль генерального директора. Все остальное нейронки делают уже лучше человека. Они не могут нести предпринимательские риски, не могут. . .
SDL3 для Web (WebAssembly): Вывод текста со шрифтом TTF с помощью SDL3_ttf
8Observer8 01.02.2026
Содержание блога В этой пошаговой инструкции создадим с нуля веб-приложение, которое выводит текст в окне браузера. Запустим на Android на локальном сервере. Загрузим Release на бесплатный. . .
SDL3 для Web (WebAssembly): Сборка C/C++ проекта из консоли
8Observer8 30.01.2026
Содержание блога Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
SDL3 для Web (WebAssembly): Установка Emscripten SDK (emsdk) и CMake для сборки C и C++ приложений в Wasm
8Observer8 30.01.2026
Содержание блога Для того чтобы скачать Emscripten SDK (emsdk) необходимо сначало скачать и уставить Git: Install for Windows. Следуйте стандартной процедуре установки Git через установщик. . . .
SDL3 для Android: Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 29.01.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами. Версия v3 была полностью переписана на Си, в. . .
Инструменты COM: Сохранение данный из VARIANT в файл и загрузка из файла в VARIANT
bedvit 28.01.2026
Сохранение базовых типов COM и массивов (одномерных или двухмерных) любой вложенности (деревья) в файл, с возможностью выбора алгоритмов сжатия и шифрования. Часть библиотеки BedvitCOM Использованы. . .
SDL3 для Android: Загрузка PNG с альфа-каналом с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 28.01.2026
Содержание блога SDL3 имеет собственные средства для загрузки и отображения PNG-файлов с альфа-каналом и базовой работы с ними. В этой инструкции используется функция SDL_LoadPNG(), которая. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru