将对象的生命周期用作设置器的安全性

问题描述 投票:3回答:2

我创建了一个“作用域设置器”,当它超出范围时,它会自动为变量(通常是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的生存期,因为它尚未使用?

谢谢!

c++ scope
2个回答
1
投票

[不用担心,命名的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可能需要同步,具体取决于'任务'与'线程'有关。


1
投票

通常来说,这个主意看起来不错。但是,最好使用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。

© www.soinside.com 2019 - 2024. All rights reserved.