RAII和推导出的模板参数

HC4*_*ica 8 c++ templates raii c++11

这是我经常遇到的RAII问题.我想知道是否有人有一个很好的解决方案.

从标准RAII实用程序类开始:

class RAIIHelper {
  RAIIHelper() {
    AcquireAResource();
  }
  ~RAIIHelper() {
    ReleaseTheResource();
  }
};
Run Code Online (Sandbox Code Playgroud)

现在,由于各种原因,我需要将其作为模板.我们还说它的构造函数接受模板参数类型的参数:

template <typename T>
class RAIIHelper {
  RAIIHelper(T arg) {
    AcquireAResource();
  }
  ~RAIIHelper() {
    ReleaseTheResource();
  }
};
Run Code Online (Sandbox Code Playgroud)

现在考虑使用网站:

void func() {
  RAIIHelper<SomeType> helper(someObj);
}
Run Code Online (Sandbox Code Playgroud)

SomeType当它可以从中推断时必须写出来很烦人someObj,因此我编写了一个辅助函数来推断出类型:

template <typename T>
RAIIHelper<T> makeRAIIHelper(T arg) {
  return RAIIHelper<T>(arg);
}
Run Code Online (Sandbox Code Playgroud)

现在我可以像这样使用它:

void func() {
  auto helper = makeRAIIHelper(someObj);
}
Run Code Online (Sandbox Code Playgroud)

很棒,对吧?除了有一个障碍:RAIIHelper现在需要是可复制的或可移动的,并且释放资源的析构函数可能被调用两次:一次用于返回的临时值makeRAIIHelper,一次用于调用函数中的局部变量.

实际上,我的编译器执行RVO,并且只调用析构函数一次.但是,这不能保证.这可以从以下事实看出:如果我尝试给出RAIIHelper一个= delete'd move构造函数,代码就不再编译了.

我可以向RAIIHelper添加额外的状态,以便它知道ReleaseTheResource()在移动之后不会调用,但这是额外的工作,在我添加makeRAIIHelper()以获得类型扣除之前是不必要的.

有没有办法可以获得类型演绎,而无需添加额外的状态RAIIHelper

nos*_*sid 8

有一个非常简单的解决方案:使用对临时对象的引用,而不是将其复制到局部变量中.

void func()
{
    auto&& helper = makeRAIIHelper(someObj);
}
Run Code Online (Sandbox Code Playgroud)

  • 如果你将`return RAIIHelper <T>(arg);`替换为"direct-initialization"àla`return{arg}`,则该类型不需要是可移动的. (5认同)
  • @ StianV.Svedenborg该临时值的生命周期延长到范围结束. (4认同)
  • @KerrekSB IIRC复制列表初始化与直接列表初始化相同,只是前者不能与显式构造函数一起使用. (2认同)