允许l值引用并禁止r值引用作为函数参数?

时间:2014-09-24 17:57:40

标签: c++ c++11 rvalue-reference

所以我有一个管理资源的类。与std::mutex类似,它有acquirerelease方法。要成为一名优秀的RAII风格的程序员,我想将模拟实现为std::unique_lock,以防止资源被永久获取。但是,出于语义原因,acquirereleaseconst函数(相信我这一点)。

这意味着我的RAII类的构造函数具有RAIIType( const T &)的签名。这个问题是,rvalue也会绑定到它。我希望选择SO的大脑来阻止这种情况的发生。

编码方面:

class ResourceType
{
public:
   void acquire() const{}
   void release() const{}
};

template< class T >
class RAIIClass
{
public:
   RAIIClass(const T & in_t) : t(in_t) { t.acquire(); }
   ~RAIIClass() { t.release(); }
private:
   const T & t;
};

ResourceType foo() { return ResourceType(); }

int main()
{
   ResourceType x1;
   const ResourceType & x2(x1);

   {
      RAIIClass<ResourceType> x(x1); //Allowable
   }
   {
      RAIIClass<ResourceType> x(x2); //Allowable
   }
   {
      RAIIClass<ResourceType> x(foo()); //Currently allowable, would like to disallow.
   }
}

有什么想法吗?

2 个答案:

答案 0 :(得分:8)

添加此构造函数:

RAIIClass(const T&&) = delete;

这将绑定到const或非const rvalues,其中const和非const lvalues将更喜欢您现有的构造函数:

RAIIClass(const T & in_t) : t(in_t) { t.acquire(); }

答案 1 :(得分:2)

禁止创建临时管理器的替代方法是更改​​管理器类,以便在使用临时(Demo at Coliru)调用时在内部存储托管对象:

template< class T >
class RAIIClass;
template <typename T>
RAIIClass<T> make_guard(T&&);

template< class T >
class RAIIClass
{
public:
   ~RAIIClass() { t.release(); }

private:
   friend RAIIClass make_guard<>(T&&);
   RAIIClass(T&& in_t) : t(std::forward<T>(in_t)) { t.acquire(); }

   T t;
};

template <typename T>
RAIIClass<T> make_guard(T&& t)  {
   return {std::forward<T>(t)};
}

ResourceType foo() { return {}; }

int main()
{
   ResourceType x1;
   const ResourceType & x2(x1);

   {
      auto x = make_guard(x1); //Allowable
   }
   {
      auto x = make_guard(x2); //Allowable
   }
   {
      auto x = make_guard(foo()); //Allowable too.
   }
}