Я работаю во встроенной среде микроконтроллера, которая использует глобальные переменные. Некоторые из этих глобальных переменных имеют нетривиальные конструкторы и деструкторы и страдают от проблемы статического порядка инициализации. Мне нужно, чтобы порядок был четко определен и находился под моим контролем. Обычное решение состоит в использовании функции со статической переменной, определенной внутри:
Type& GetObject()
{
static Type g_Object;
return g_Object;
}
При первом использовании GetObject() будет создана локальная статическая переменная, которая может быть частью четко определенного порядка инициализации:
int main()
{
...
GetObject1();
GetObject2();
...
}
Но что, если я хочу, чтобы разрушение произошло в определенный момент и в четко определенном порядке? (В данном случае, прямо перед входом в режим выключения микроконтроллера.)
Если бы программа должна была нормально завершить работу в размещенной среде, разрушение произошло бы в порядке, противоположном инициализации, и это нормально. Однако в этом случае программа не завершится нормально, поэтому это неприменимо. Возможно, можно использовать std::exit (не пробовал), но он также выполняет дополнительные операции, которые не нужны (например, очистку потоков C).
Потенциальное решение
Это решение включает в себя тип объединения оболочек, который полагается на то, что пользователь выполняет явную инициализацию и уничтожение. Конструктор инициализирует член тривиального типа, что делает его безопасным для инициализации в любом глобальном порядке, а деструктор ничего не делает.
Под капотом используется размещение new для инициализации и вызов деструктора базового типа при уничтожении.
Пользователь должен правильно использовать оболочку — в противном случае поведение неопределенное.
#include
#include
template
union Lazy_t
{
public:
inline Lazy_t() : m_uninitialized{} {}
inline ~Lazy_t() {}
template
inline void Initialize(Args&&... args) { ::new (&m_initialized) T(std::forward(args)...); }
inline void Destroy() { m_initialized.~T(); }
inline T& operator* () { return m_initialized; }
inline const T& operator* () const { return m_initialized; }
inline T* operator->() { return &m_initialized; }
inline const T* operator->() const { return &m_initialized; }
private:
struct Uninitialized_t {};
Uninitialized_t m_uninitialized;
T m_initialized;
};
Его можно использовать следующим образом:
struct NonTrivial_t
{
NonTrivial_t() : m_value{} { m_value = new int{}; }
~NonTrivial_t() { delete m_value; }
int* m_value;
};
Lazy_t g_Object1;
Lazy_t g_Object2;
void Main()
{
// ... microcontroller initialization ...
g_Object1.Initialize();
g_Object2.Initialize();
// ...
*g_Object1->m_value = 1;
*g_Object2->m_value = 2;
// ...
g_Object2.Destroy();
g_Object1.Destroy();
// ... microcontroller de-initialization and enter shutdown ...
}
Есть ли какие-либо проблемы с этим решением?
Приложение: отложенный тип (обертка) с проверками безопасности:
#include
template
class SafeLazy_t
{
public:
inline SafeLazy_t()
: m_lazy{}
#ifndef NDEBUG
, m_initialized{}
#endif
{}
inline ~SafeLazy_t()
{
#ifndef NDEBUG
assert(!m_initialized);
#endif
}
template
inline void Initialize(Args&&... args)
{
#ifndef NDEBUG
assert(!m_initialized);
#endif
m_lazy.Initialize(std::forward(args)...);
#ifndef NDEBUG
m_initialized = true;
#endif
}
inline void Destroy()
{
#ifndef NDEBUG
assert(m_initialized);
#endif
m_lazy.Destroy();
#ifndef NDEBUG
m_initialized = false;
#endif
}
inline T& operator*()
{
#ifndef NDEBUG
assert(m_initialized);
#endif
return *m_lazy;
}
inline const T& operator*() const
{
#ifndef NDEBUG
assert(m_initialized);
#endif
return *m_lazy;
}
inline InnerLazy_t& operator->()
{
#ifndef NDEBUG
assert(m_initialized);
#endif
return m_lazy;
}
inline const InnerLazy_t& operator->() const
{
#ifndef NDEBUG
assert(m_initialized);
#endif
return m_lazy;
}
private:
Lazy_t m_lazy;
#ifndef NDEBUG
bool m_initialized;
#endif
};
Подробнее здесь: https://stackoverflow.com/questions/798 ... -variables
Явное управление инициализацией и уничтожением глобальных переменных ⇐ C++
Программы на C++. Форум разработчиков
1768381204
Anonymous
Я работаю во встроенной среде микроконтроллера, которая использует глобальные переменные. Некоторые из этих глобальных переменных имеют нетривиальные конструкторы и деструкторы и страдают от проблемы статического порядка инициализации. Мне нужно, чтобы порядок был четко определен и находился под моим контролем. Обычное решение состоит в использовании функции со статической переменной, определенной внутри:
Type& GetObject()
{
static Type g_Object;
return g_Object;
}
При первом использовании GetObject() будет создана локальная статическая переменная, которая может быть частью четко определенного порядка инициализации:
int main()
{
...
GetObject1();
GetObject2();
...
}
[b]Но что, если я хочу, чтобы разрушение произошло в определенный момент и в четко определенном порядке?[/b] (В данном случае, прямо перед входом в режим выключения микроконтроллера.)
Если бы программа должна была нормально завершить работу в размещенной среде, разрушение произошло бы в порядке, противоположном инициализации, и это нормально. Однако в этом случае программа не завершится нормально, поэтому это неприменимо. Возможно, можно использовать std::exit (не пробовал), но он также выполняет дополнительные операции, которые не нужны (например, очистку потоков C).
Потенциальное решение
Это решение включает в себя тип объединения оболочек, который полагается на то, что пользователь выполняет явную инициализацию и уничтожение. Конструктор инициализирует член тривиального типа, что делает его безопасным для инициализации в любом глобальном порядке, а деструктор ничего не делает.
Под капотом используется размещение new для инициализации и вызов деструктора базового типа при уничтожении.
Пользователь должен правильно использовать оболочку — в противном случае поведение неопределенное.
#include
#include
template
union Lazy_t
{
public:
inline Lazy_t() : m_uninitialized{} {}
inline ~Lazy_t() {}
template
inline void Initialize(Args&&... args) { ::new (&m_initialized) T(std::forward(args)...); }
inline void Destroy() { m_initialized.~T(); }
inline T& operator* () { return m_initialized; }
inline const T& operator* () const { return m_initialized; }
inline T* operator->() { return &m_initialized; }
inline const T* operator->() const { return &m_initialized; }
private:
struct Uninitialized_t {};
Uninitialized_t m_uninitialized;
T m_initialized;
};
Его можно использовать следующим образом:
struct NonTrivial_t
{
NonTrivial_t() : m_value{} { m_value = new int{}; }
~NonTrivial_t() { delete m_value; }
int* m_value;
};
Lazy_t g_Object1;
Lazy_t g_Object2;
void Main()
{
// ... microcontroller initialization ...
g_Object1.Initialize();
g_Object2.Initialize();
// ...
*g_Object1->m_value = 1;
*g_Object2->m_value = 2;
// ...
g_Object2.Destroy();
g_Object1.Destroy();
// ... microcontroller de-initialization and enter shutdown ...
}
[b]Есть ли какие-либо проблемы с этим решением?[/b]
Приложение: отложенный тип (обертка) с проверками безопасности:
#include
template
class SafeLazy_t
{
public:
inline SafeLazy_t()
: m_lazy{}
#ifndef NDEBUG
, m_initialized{}
#endif
{}
inline ~SafeLazy_t()
{
#ifndef NDEBUG
assert(!m_initialized);
#endif
}
template
inline void Initialize(Args&&... args)
{
#ifndef NDEBUG
assert(!m_initialized);
#endif
m_lazy.Initialize(std::forward(args)...);
#ifndef NDEBUG
m_initialized = true;
#endif
}
inline void Destroy()
{
#ifndef NDEBUG
assert(m_initialized);
#endif
m_lazy.Destroy();
#ifndef NDEBUG
m_initialized = false;
#endif
}
inline T& operator*()
{
#ifndef NDEBUG
assert(m_initialized);
#endif
return *m_lazy;
}
inline const T& operator*() const
{
#ifndef NDEBUG
assert(m_initialized);
#endif
return *m_lazy;
}
inline InnerLazy_t& operator->()
{
#ifndef NDEBUG
assert(m_initialized);
#endif
return m_lazy;
}
inline const InnerLazy_t& operator->() const
{
#ifndef NDEBUG
assert(m_initialized);
#endif
return m_lazy;
}
private:
Lazy_t m_lazy;
#ifndef NDEBUG
bool m_initialized;
#endif
};
Подробнее здесь: [url]https://stackoverflow.com/questions/79865206/explicit-control-of-initialization-destruction-of-global-variables[/url]
Ответить
1 сообщение
• Страница 1 из 1
Перейти
- Кемерово-IT
- ↳ Javascript
- ↳ C#
- ↳ JAVA
- ↳ Elasticsearch aggregation
- ↳ Python
- ↳ Php
- ↳ Android
- ↳ Html
- ↳ Jquery
- ↳ C++
- ↳ IOS
- ↳ CSS
- ↳ Excel
- ↳ Linux
- ↳ Apache
- ↳ MySql
- Детский мир
- Для души
- ↳ Музыкальные инструменты даром
- ↳ Печатная продукция даром
- Внешняя красота и здоровье
- ↳ Одежда и обувь для взрослых даром
- ↳ Товары для здоровья
- ↳ Физкультура и спорт
- Техника - даром!
- ↳ Автомобилистам
- ↳ Компьютерная техника
- ↳ Плиты: газовые и электрические
- ↳ Холодильники
- ↳ Стиральные машины
- ↳ Телевизоры
- ↳ Телефоны, смартфоны, плашеты
- ↳ Швейные машинки
- ↳ Прочая электроника и техника
- ↳ Фототехника
- Ремонт и интерьер
- ↳ Стройматериалы, инструмент
- ↳ Мебель и предметы интерьера даром
- ↳ Cантехника
- Другие темы
- ↳ Разное даром
- ↳ Давай меняться!
- ↳ Отдам\возьму за копеечку
- ↳ Работа и подработка в Кемерове
- ↳ Давай с тобой поговорим...
Мобильная версия