如何解决手动寿命管理,替代安置
我有一段带有回调的低级代码:Init
和Cleanup
,以及其他。我不控制回调的参数。我选择使用全局变量来管理状态,例如class state
。
这是我可以使用的简单结构:
std::unique_ptr<state> s;
void Init() {
s = make_unique<state>();
}
void Cleanup() {
s.reset();
}
这很简单,很容易解释。主要缺点:它使用堆,这意味着会牺牲性能,并且分配可能会失败。
或者,我可以使用类似于以下内容的构造:
alignas(state) unsigned char s_buf[sizeof(state)];
void Init() {
state* s = new(s_buf) state;
}
void Cleanup() {
state* s = reinterpret_cast<state*>(s_buf);
s->~T();
}
现在我不使用堆,但是它更丑陋并且更容易出错,而且我什至不确定在某个地方是否存在未定义的行为。我也许可以将其封装在包装器类中,但是有很多地方可能出错。
是否有任何通用的结构来实现我要完成的任务,即具有类似unique_ptr
的类但没有堆分配?
解决方法
我认为您可以 将std::unique_ptr
与带有重载的new
和delete
运算符的类一起使用:
#include <cstddef>
#include <type_traits>
#include <memory>
template <class T>
struct global_type : T {
static void* operator new (size_t) {
static std::aligned_storage_t<sizeof(global_type),alignof(global_type)> m_store;
return &m_store;
}
static void operator delete(void*) {
}
};
struct state {
int foo;
};
std::unique_ptr<global_type<state>> ptr;
void Init() {
ptr = std::make_unique<global_type<state>>();
ptr->foo = 42;
}
void CleanUp() {
ptr.reset();
}
std::unique_ptr
将在global_type
中使用静态重载,因此不会达到任何堆分配,并且开销应为零。
由于需要aligned_storage
来提供适合存储所提供大小和对齐方式的存储空间,因此应该没有未定义的行为。
但是,我建议仅使用std::optional
作为注释中提到的光谱,除非特别需要unique_ptr
。
将评论扩展为答案:
C ++ 17为此提供了完美的工具:std::optional
。
它完全可以执行您的操作,除了它还可以跟踪存储中当前是否有对象。除非您要进行嵌入并且标记的额外大小很重要,否则应该很好:
#include <optional>
struct state {
int foo;
};
static std::optional<state> currentState;
void Init() {
currentState = state{ 42 };
}
void CleanUp() {
currentState = std::nullopt;
}
void doStuff() {
currentState->foo += 12;
}
void doStuffOnlyIfInitialized() {
if (currentState) {
currentState->foo += 12;
}
}
请注意,如果您两次调用Init
,或者两次调用CleanUp
,则此处的代码将会很高兴。如果要防止出现这种情况,可以在assert(!currentState)
的开头添加Init
,在assert(currentState)
的开头添加CleanUp
。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。