我创建了一个“作用域设置器”,当它超出范围时,它会自动为变量(通常是POD)分配一个值。我主要使用它来跟踪当前执行是否在一定范围内。
template<typename T>
struct FScopedSetter
{
FScopedSetter(T& InObject, T InbOutOfScopeValue)
{
Object = &InObject;
bOutOfScopeValue = InbOutOfScopeValue;
}
virtual ~FScopedSetter()
{
*Object = bOutOfScopeValue;
}
T* Object;
T bOutOfScopeValue;
};
// Example:
bool bInTaskA = false;
void TaskA()
{
bInTaskA = true;
FScopedSetter<bool> Setter(bInTaskA, false);
// ..
}
这在以后我决定在TaskA中放一个额外的return语句,但是忘记在其前面加上bInTaskA = false时应该更安全。
我的问题是:这是否正确,并且至少在使用POD时,只要我命名为FScopedSetter对象,它是否(总是)可以正常工作?我有点担心编译器可能会决定它可以尽早结束setter的生存期,因为它尚未使用?
谢谢!
[不用担心,命名的setter对象在作用域末尾之前不会被销毁。它会像往常一样被破坏:以相反的顺序构造。
但是,发布的代码存在一些小问题。首先,FScopedSetter
的析构函数不必是虚拟的,因为这里没有继承。
并且T::operator=(const T&)
绝不能抛出(更好地声明为noexcept
),否则,作用域分配器类的析构函数可能会抛出。如果您的代码针对的是C ++ 11,则最好将bOutOfScopeValue
移至*Object
:
FScopedSetter(T& InObject, T InbOutOfScopeValue)
: Object(&InObject)
, bOutOfScopeValue(InbOutOfScopeValue)
{
}
~FScopedSetter()
{
static_assert(noexcept(*Object = std::move(bOutOfScopeValue)),
"Move assignment of your data type may throw. Make sure it doesn't.");
*Object = std::move(bOutOfScopeValue);
}
并且访问*Object
可能需要同步,具体取决于'任务'与'线程'有关。
通常来说,这个主意看起来不错。但是,最好使用shared_ptr<>
以确保从属对象不会过早超出范围,这会使您的程序崩溃。
template<typename T>
struct FScopedSetter
{
FScopedSetter(std::shared_ptr<T> InObject, T InbOutOfScopeValue)
: Object(InObject), bOutOfScopeValue(InbOutOfScopeValue) {}
virtual ~FScopedSetter()
{
*Object = bOutOfScopeValue;
}
std::shared_ptr<T> Object;
T bOutOfScopeValue;
};
// Example:
auto bInTaskA = make_shared<bool>(false);
void TaskA()
{
*bInTaskA = true;
FScopedSetter<bool> Setter(bInTaskA, false);
// ..
}
您也可以直接使用shared_ptr
代替您的类,只需检查它是否不是NULL。但是,您的方式允许在bOutOfScopeValue
中传递一些其他信息,从而使其变得更好。另外,请在上述代码中的适当位置检查NULL。