如何在自定义删除器的情况下复制unique_ptr

how to make copy of unique_ptr wih custom deleter

本文关键字:复制 情况下 unique ptr 自定义 删除      更新时间:2023-10-16

如果我使用自定义删除器复制unique_ptr,则会出现编译错误。请有人帮帮我.

#include <iostream>
#include<memory>
#include <algorithm>
using namespace std;
auto del = [](int *p) { cout <<"obj deleted "<<endl;delete p;};
int main()
{
unique_ptr<int, decltype(del)> p1(new int(10), del);
unique_ptr<int,decltype(del)> p2;
p2 = std::move(p1);
}

错误:

C:Program Files (x86)CodeBlocksMinGWlibgccmingw325.1.0includec++tuple||In instantiation of 'constexpr std::_Head_base<_Idx, _Head, true>::_Head_base() [with unsigned int _Idx = 1u; _Head = <lambda(int*)>]':|
C:Program Files (x86)CodeBlocksMinGWlibgccmingw325.1.0includec++tuple|353|required from 'constexpr std::_Tuple_impl<_Idx, _Head>::_Tuple_impl() [with unsigned int _Idx = 1u; _Head = <lambda(int*)>]'|
C:Program Files (x86)CodeBlocksMinGWlibgccmingw325.1.0includec++tuple|202|required from 'constexpr std::_Tuple_impl<_Idx, _Head, _Tail ...>::_Tuple_impl() [with unsigned int _Idx = 0u; _Head = int*; _Tail = {<lambda(int*)>}]'|
C:Program Files (x86)CodeBlocksMinGWlibgccmingw325.1.0includec++tuple|602|required from 'constexpr std::tuple<_T1, _T2>::tuple() [with _T1 = int*; _T2 = <lambda(int*)>]'|
C:Program Files (x86)CodeBlocksMinGWlibgccmingw325.1.0includec++bitsunique_ptr.h|158|required from 'constexpr std::unique_ptr<_Tp, _Dp>::unique_ptr() [with _Tp = int; _Dp = <lambda(int*)>]'|
F:3dC++CodeProjectHellomain.cpp|10|required from here|
C:Program Files (x86)CodeBlocksMinGWlibgccmingw325.1.0includec++tuple|59|error: use of deleted function '<lambda(int*)>::<lambda>()'|
F:3dC++CodeProjectHellomain.cpp|6|note: a lambda closure type has a deleted default constructor|
C:Program Files (x86)CodeBlocksMinGWlibgccmingw325.1.0includec++bitsunique_ptr.h||In instantiation of 'std::unique_ptr<_Tp, _Dp>& std::unique_ptr<_Tp, _Dp>::operator=(std::unique_ptr<_Tp, _Dp>&&) [with _Tp = int; _Dp = <lambda(int*)>]':|
F:3dC++CodeProjectHellomain.cpp|11|required from here|
C:Program Files (x86)CodeBlocksMinGWlibgccmingw325.1.0includec++bitsunique_ptr.h|252|error: use of deleted function '<lambda(int*)>&<lambda(int*)>::operator=(const<lambda(int*)>&)'|
F:3dC++CodeProjectHellomain.cpp|6|note: a lambda closure type has a deleted copy assignment operator|
||=== Build failed: 2 error(s), 8 warning(s) (0 minute(s), 1 second(s)) ===|

您在声明p2时遇到的问题是 lambda 的类型不是默认可构造的。因此,指针类型的每个声明都需要传递一个删除程序的实例。

您可以通过将删除程序 lambda 替换为默认可构造的显式函子结构来解决此问题。然后,指针类型的每个实例将能够创建自己的删除器对象实例。

struct MyDeleter
{
void operator()(int* p){cout << "deleted" << endl; delete p;}
};
int main()
{
//don't need to specify an instance of the deleter since it is default_constructible.
unique_ptr<int, MyDeleter> p1(new int(10)); 
unique_ptr<int, MyDeleter> p2;
p2 = std::move(p1);
}

编辑: 正如@super所说,赋值行的问题还在于(C++20之前(lambda也不是CopyAssignable的。我上面发布的函子方法解决了这两个问题。

两个问题。

  1. 在 C++20 之前,lambda 闭包类型不是 DefaultConstructible;这导致将其用作删除器的std::unique_ptr也不是 DefaultConstructible。

闭包类型不是默认构造的。闭包类型具有a deleted (until C++14)no (since C++14)默认构造函数。(至C++20(

如果未指定捕获,则闭包类型具有默认的默认构造函数。否则,它没有默认构造函数(这包括存在捕获默认的情况,即使它实际上没有捕获任何内容(。(自C++20起(

  1. 在 C++20 之前,lambda 闭包类型不是 CopyAssignable;这导致将其用作删除程序的std::unique_ptr也不是 CopyAssignable。
复制指派运算符

定义为已删除(并且未声明移动指派运算符(。闭包类型不可复制分配。(至C++20(

如果未指定捕获,则闭包类型具有缺省复制指派运算符和缺省移动指派运算符。否则,它有一个已删除的复制分配运算符(这包括存在捕获默认值的情况,即使它实际上没有捕获任何内容(。(自C++20起(

这意味着,您的代码将从 C++20 开始工作,因为 lambda 不指定捕获。在此之前,您可以改用std::function;例如std::function<void(int*)> del = [](int *p) { cout <<"obj deleted "<<endl;delete p;};

您会收到一条错误消息,因为在这种情况下,unique_ptr上没有默认构造器,因此它们始终被启动

但你可以做到

auto del = [](int *p) { cout <<"obj deleted "<<endl;delete p;};
int main()
{
unique_ptr<int, decltype(del)> p1(new int(10), del);
unique_ptr<int,decltype(del)> p2(std::move(p1));
}

这里有两个错误(如错误消息所示(:您不能复制分配 lambda(在构造p1时需要(,也不能默认构造 lambda(在p2的默认初始化中需要(。

这将修复以下两个错误:

auto del = [](int *p) { cout <<"obj deleted "<<endl;delete p;};
int main()
{
unique_ptr<int, decltype(del)> p1(new int(10), std::move(del));
unique_ptr<int, decltype(del)> p2 = std::move(p1);
}

但请注意,您的 lambda 只有一个实例会以这种方式存在。要为多个唯一指针生成多个 lambda 实例,您可以从函数返回它,使用std::function或编写函子结构(请参阅其他答案(。

您得到的错误是因为 lambda 不是默认构造的。当您声明p2时,您不会传递参数以用作删除器,因此编译器抱怨无法默认构造它。

这个答案已经涵盖了使用自定义删除器的干净方法。但是,如果必须对同一类的对象使用不同的删除器,则必须在每个智能指针的构造中传递删除器,或者使用默认可构造的类型,以便nullptr可以具有"null"删除器对象。

auto del = [](int *p) { cout << "obj deleted " << endl; delete p; };
int main() {
unique_ptr<int, std::function<void(int*)>> p1(new int(10), del);
unique_ptr<int, std::function<void(int*)>> p2;
p2 = std::move(p1);
}

这样,您不仅不必在没有管理对象时分配删除器,而且您可以定义和使用其他删除器,这些删除器始终与创建它们的对象一起移动。

相关文章: