繁体   English   中英

如何使用自定义删除器复制unique_ptr

[英]how to make copy of unique_ptr wih custom deleter

如果我使用自定义删除器复制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)\CodeBlocks\MinGW\lib\gcc\mingw32\5.1.0\include\c++\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)\CodeBlocks\MinGW\lib\gcc\mingw32\5.1.0\include\c++\tuple|353|required from 'constexpr std::_Tuple_impl<_Idx, _Head>::_Tuple_impl() [with unsigned int _Idx = 1u; _Head = <lambda(int*)>]'|
C:\Program Files (x86)\CodeBlocks\MinGW\lib\gcc\mingw32\5.1.0\include\c++\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)\CodeBlocks\MinGW\lib\gcc\mingw32\5.1.0\include\c++\tuple|602|required from 'constexpr std::tuple<_T1, _T2>::tuple() [with _T1 = int*; _T2 = <lambda(int*)>]'|
C:\Program Files (x86)\CodeBlocks\MinGW\lib\gcc\mingw32\5.1.0\include\c++\bits\unique_ptr.h|158|required from 'constexpr std::unique_ptr<_Tp, _Dp>::unique_ptr() [with _Tp = int; _Dp = <lambda(int*)>]'|
F:\3d\C++CodeProject\Hello\main.cpp|10|required from here|
C:\Program Files (x86)\CodeBlocks\MinGW\lib\gcc\mingw32\5.1.0\include\c++\tuple|59|error: use of deleted function '<lambda(int*)>::<lambda>()'|
F:\3d\C++CodeProject\Hello\main.cpp|6|note: a lambda closure type has a deleted default constructor|
C:\Program Files (x86)\CodeBlocks\MinGW\lib\gcc\mingw32\5.1.0\include\c++\bits\unique_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:\3d\C++CodeProject\Hello\main.cpp|11|required from here|
C:\Program Files (x86)\CodeBlocks\MinGW\lib\gcc\mingw32\5.1.0\include\c++\bits\unique_ptr.h|252|error: use of deleted function '<lambda(int*)>&<lambda(int*)>::operator=(const<lambda(int*)>&)'|
F:\3d\C++CodeProject\Hello\main.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的类型不是默认的可构造的 因此,指针类型的每个声明都需要传递一个删除器的实例。

您可以通过使用默认可构造的显式functor结构替换deleter 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所说,赋值行的问题也是(pre-c ++ 20)lambdas也不是CopyAssignable 我上面发布的仿函数方法修复了这两个问题。

两个问题。

  1. 在C ++之前,20个lambda闭包类型不是DefaultConstructible; 这导致std::unique_ptr使用它作为删除器而不是DefaultConstructible。

闭包类型不是DefaultConstructible。 Closure类型有a deleted (until C++14) no (since C++14)默认构造函数。 (直到C ++ 20)

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

  1. 在C ++之前,20个lambda闭包类型不是CopyAssignable; 这导致std::unique_ptr使用它作为删除器而不是CopyAssignable。

复制赋值运算符被定义为已删除(并且未声明移动赋值运算符)。 闭包类型不是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或编写一个functor结构(参见其他答案)。

你得到的错误是因为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);
}

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM