Я работаю над средним встроенным приложением в C, используя OO-подобные методы. Мои "классы" - это модули .h / .c, использующие структуры данных и структуры указателей функций для эмуляции инкапсуляции, полиморфизма и внедрения зависимостей.
Теперь можно ожидать, что myModule_create(void)
функция придет с myModule_destroy(pointer)
аналогом. Но когда проект внедряется, ресурсы, которые реально создаются, никогда не должны высвобождаться.
Я имею в виду, что если у меня есть 4 последовательных порта UART и я создаю 4 экземпляра UART с их необходимыми выводами и настройками, нет абсолютно никакой причины когда-либо хотеть уничтожить UART # 2 в какой-то момент во время выполнения.
Итак, следуя принципу ЯГНИ (тебе это не понадобится), я должен опустить деструкторы? Это кажется мне чрезвычайно странным, но я не могу придумать, как их использовать; ресурсы освобождаются при выключении устройства.
источник
myModule_create(void)
функция? Вы можете просто жестко закодировать конкретные экземпляры, которые вы ожидаете использовать в интерфейсе, который вы предоставляете.Ответы:
Гламперт прав; здесь нет необходимости в деструкторах. Они просто создают раздувание кода и подводный камень для пользователей (использование объекта после вызова его деструктора - неопределенное поведение).
Тем не менее, вы должны быть уверены, что нет необходимости избавляться от объектов. Например, вам нужен объект для UART, который в данный момент не используется?
источник
Самый простой способ обнаружения утечек памяти, который я обнаружил, - это возможность корректно завершить работу вашего приложения. Многие компиляторы / среды предоставляют способ проверки памяти, которая все еще выделяется при выходе из приложения. Если его нет, обычно есть способ добавить код прямо перед выходом, который может это понять.
Итак, я бы определенно предоставил конструкторы, деструкторы и логику выключения даже во встроенной системе, которая «теоретически» никогда не должна выходить из-за простоты обнаружения утечек памяти. На самом деле, обнаружение утечек памяти еще более важно, если код приложения никогда не завершается.
источник
В моей разработке, в которой широко используются непрозрачные типы данных для реализации ОО-подобного подхода, я тоже задавался этим вопросом. Сначала я был решительно настроен уничтожить деструктора с точки зрения YAGNI, а также с точки зрения MISRA «мертвый код». (У меня было много ресурсов, это не было соображением.)
Однако ... отсутствие деструктора может усложнить тестирование, как при автоматизированном модульном / интеграционном тестировании. Обычно каждый тест должен поддерживать настройку / демонтаж, чтобы объекты могли быть созданы, обработаны, а затем уничтожены. Они уничтожаются, чтобы обеспечить чистую, незапятнанную отправную точку для следующего теста. Для этого классу нужен деструктор.
Поэтому, по моему опыту, «нет» в YAGNI оказывается «есть», и я закончил тем, что создал деструкторы для каждого класса, думал ли я, нуждаюсь ли я в этом или нет. Даже если я пропущу тестирование, по крайней мере, правильно разработанный деструктор для плохого слоба, который следует за мной, будет иметь его. (И, что гораздо менее важно, он делает код более пригодным для повторного использования, поскольку его можно использовать в среде, где он будет уничтожен.)
Хотя это относится к YAGNI, оно не обращается к мертвому коду. Для этого я обнаружил, что макрос условной компиляции, например, #define BUILD_FOR_TESTING, позволяет исключить деструктор из окончательной производственной сборки.
Делая это следующим образом: у вас есть деструктор для тестирования / повторного использования в будущем, и вы удовлетворяете целям разработки YAGNI и правилам «без мертвых кодов».
источник
Вы можете иметь неоперативный деструктор, что-то вроде
затем установить деструктор,
Uart
возможно, с помощью(добавьте подходящий состав, если это необходимо)
Не забудьте документировать. Может быть, вы хотите даже
Альтернативно, особый случай в общем коде, вызывающем деструктор, - это случай, когда функция указателя деструктора
NULL
должна избегать его вызова.источник