【问题标题】:Safety of using an object's lifetime as setter使用对象的生命周期作为设置器的安全性
【发布时间】:2019-09-26 11:50:26
【问题描述】:

我制作了一个“作用域设置器”,当它超出作用域时,它会自动为变量赋值,通常是 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。

我的问题是:假设我将 FScopedSetter 对象命名为 FScopedSetter 对象,这是否正确并且它(总是)可以正常工作,至少在使用 POD 时?我有点担心编译器可能会因为未使用而决定它可以提前结束 setter 的生命周期?

谢谢!

【问题讨论】:

  • 据我所知,这很好,虽然我会使用范围保护模式的一些通用实现而不是定制的。

标签: c++ scope


【解决方案1】:

别担心,一个命名的 setter 对象不会在它的作用域结束之前被销毁。它将像往常一样被销毁:以相反的构建顺序。

但是,发布的代码存在一些小问题。一方面,FScopedSetter 的析构函数不必是虚拟的,因为这里没有继承。

并且T::operator=(const T&amp;) 绝不能抛出(最好声明为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 可能需要同步,这取决于“任务”是否与“线程”有关。

【讨论】:

    【解决方案2】:

    一般来说,这个想法似乎很好。 但是最好使用shared_ptr&lt;&gt; 来确保依赖对象不会过早超出范围,否则会导致程序崩溃。

    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。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-16
      • 1970-01-01
      • 2018-05-17
      • 1970-01-01
      • 2011-04-28
      相关资源
      最近更新 更多