Явное управление инициализацией и уничтожением глобальных переменныхC++

Программы на C++. Форум разработчиков
Ответить
Anonymous
 Явное управление инициализацией и уничтожением глобальных переменных

Сообщение Anonymous »

Я работаю во встроенной среде микроконтроллера, которая использует глобальные переменные. Некоторые из этих глобальных переменных имеют нетривиальные конструкторы и деструкторы и страдают от проблемы статического порядка инициализации. Мне нужно, чтобы порядок был четко определен и находился под моим контролем. Обычное решение состоит в использовании функции со статической переменной, определенной внутри:
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
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

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

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C++»