std :: unique_ptr中的不可复制删除器

时间:2014-05-12 15:29:27

标签: c++ c++11 move unique-ptr

我一直在寻找另一个问题(this one)的解决方案。似乎应该可以为可以解锁互斥锁的unique_ptr实例创建自定义删除器。

例如,

#include <mutex>
#include <memory>

struct LockDeleter
{
  std::unique_lock<std::mutex> lock_;

  LockDeleter(std::mutex& m) : lock_(m) {}
  void operator()(void*) { lock_.unlock(); }
};

int main()
{
  std::mutex moo;

  {
    std::unique_ptr<int, LockDeleter> ptr(new int(42), LockDeleter(moo));
  }
}

在VS2013 express下编译,我得到了

  

错误1错误C2280:&#39; std :: unique_lock :: unique_lock(const std :: unique_lock&amp;)&#39; :尝试引用已删除的函数

  

此诊断发生在编译器生成的函数&#39; LockDeleter :: LockDeleter(const LockDeleter&amp;)&#39;

现在,我似乎无法强制移动锁删除器实例,而不是使用std::move复制...甚至向{{添加显式移动构造函数1}}没有帮助,删除的拷贝构造函数仍然被调用。

那么,我是在做傻事,还是LockDeleter删除者总是可以复制?

1 个答案:

答案 0 :(得分:1)

unique_ptr需要支持可移动构造的删除者; 20.7.1.2.1 [unique.ptr.single.ctor]

  

9 - [...]如果[删除者类型] D是非引用类型A,那么[双参数构造函数]签名是:

unique_ptr(pointer p, const A& d);
unique_ptr(pointer p, A&& d);
     

[...]

     

12 - 需要: [...]

     
      
  • [if d是非const rvalue,然后D应满足MoveConstructible的要求(表20),D的移动构造函数不得抛出一个例外。此unique_ptr将保留从d构建的值移动。 [...]
  •   

如果我们显式添加一个移动构造函数并从LockDeleter删除复制构造函数,那么我们会得到一条信息更丰富的错误消息; http://rextester.com/XFYUG91939

Error(s):
C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\INCLUDE\memory(1243) : error C2280: 'LockDeleter::LockDeleter(const LockDeleter &)' : attempting to reference a deleted function
        source_file.cpp(10) : see declaration of 'LockDeleter::LockDeleter'
        C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\INCLUDE\memory(1241) : while compiling class template member function 'std::_Unique_ptr_base<_Ty,_Dx,false>::_Unique_ptr_base(int *,_Dx)'
        with
        [
            _Ty=int
,            _Dx=LockDeleter
        ]
        C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\INCLUDE\memory(1380) : see reference to function template instantiation 'std::_Unique_ptr_base<_Ty,_Dx,false>::_Unique_ptr_base(int *,_Dx)' being compiled
        with
        [
            _Ty=int
,            _Dx=LockDeleter
        ]
        C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\INCLUDE\memory(1331) : see reference to class template instantiation 'std::_Unique_ptr_base<_Ty,_Dx,false>' being compiled
        with
        [
            _Ty=int
,            _Dx=LockDeleter
        ]
        source_file.cpp(20) : see reference to class template instantiation 'std::unique_ptr<int,LockDeleter>' being compiled

请注意提及std::_Unique_ptr_base<_Ty,_Dx,false>::_Unique_ptr_base(int *,_Dx);这表示当删除参数被移动时,它被错误地复制到内部基类中。

我能看到的唯一解决方法是使lock_变为可变,允许复制构造函数作为移动构造函数运行。