假设我有一个MyStack
类,它公开了:
class MyStack {
public:
template <typename T>
T* Push() {
Reserve(sizeof(T)); // Make sure that the buffer can hold an additional sizeof(T) bytes , realloc if needed
auto prev= _top;
_top += sizeof(T);
new (prev) T();
return reinterpret_cast<T*>(prev);
}
template <typename T>
T* Pop() {
_top -= sizeof(T);
return return reinterpret_cast<T*>(_top);
}
bool Empty() const {
return _bottom == _top;
}
private:
char* _bottom;
char* _top;
};
// Assumes all stack elements have the same type
template <typename T>
void ClearStack(MyStack& stack) {
while (!stack.Empty()) {
stack.template Pop<T>()->~T();
}
}
这里有一个隐藏的错误。在
T
中构造MyStack::Push()
可能会抛出异常,这会使堆栈缓冲区处于未定义状态(分配的空间将包含垃圾)。稍后,当调用ClearStack
时,它将尝试将垃圾重新解释为T
并调用其析构函数,这可能会导致访问冲突。是否可以通过仅修改
MyStack::Push()
来修复此错误? (限制是因为这是一个外部代码,我们希望进行最小的更改,因此更新库相对容易)我考虑过将
MyStack::Push
更改为:T* Push() {
auto prev = _top;
T t();
Reserve(sizeof(T));
_top += sizeof(T);
reinterpret_cast<T*>(prev) = std::move(t);
return prev;
}
但是它看起来很糟糕,我什至不确定它不会调用任何UB(并且会强制
T
具有move构造函数)这里有更好的解决方案来防止抛出构造函数吗? (最好是在
MyStack::Push()
内部进行小的更改) 最佳答案
这段代码怎么样:
template <typename T>
T* Push() {
Reserve(sizeof(T));
auto prev= _top;
_top += sizeof(T);
try {
new (prev) T();
return reinterpret_cast<T*>(prev);
}
catch (...) {
Unreserve(sizeof(T)); //release the memory, optional?
_top = prev;
throw;
}
}
关于c++ - 如何以异常安全的方式使用新的展示位置?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/49966422/