如何使用自定义删除器复制 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.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.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.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.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.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:d\C++CodeProject\Hello\main.cpp|10|required from here|
C:\Program Files (x86)\CodeBlocks\MinGW\lib\gcc\mingw32.1.0\include\c++\tuple|59|error: use of deleted function '<lambda(int*)>::<lambda>()'|
F:d\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.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:d\C++CodeProject\Hello\main.cpp|11|required from here|
C:\Program Files (x86)\CodeBlocks\MinGW\lib\gcc\mingw32.1.0\include\c++\bits\unique_ptr.h|252|error: use of deleted function '<lambda(int*)>&<lambda(int*)>::operator=(const<lambda(int*)>&)'|
F:d\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)) ===|
您收到一条错误消息,因为在这种情况下 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));
}
两个问题。
- 在 C++20 之前 lambda 闭包类型不是 DefaultConstructible;这导致
std::unique_ptr
将其用作删除器而不是 DefaultConstructible。
Closure types are not DefaultConstructible. Closure types have a deleted (until C++14)
no (since C++14)
default constructor. (until C++20)
If no captures are specified, the closure type has a defaulted default constructor. Otherwise, it has no default constructor (this includes the case when there is a capture-default, even if it does not actually capture anything). (since C++20)
- C++20 之前的 lambda 闭包类型不可复制;这导致
std::unique_ptr
也将其用作删除器而不是 CopyAssignable。
The copy assignment operator is defined as deleted (and the move assignment operator is not declared). Closure types are not CopyAssignable. (until C++20)
If no captures are specified, the closure type has a defaulted copy assignment operator and a defaulted move assignment operator. Otherwise, it has a deleted copy assignment operator (this includes the case when there is a capture-default, even if it does not actually capture anything). (since C++20)
这意味着,您的代码自 C++20 起即可运行,因为 lambda 未指定捕获。在此之前,您可以使用 std::function
代替;例如std::function<void(int*)> del = [](int *p) { cout <<"obj deleted "<<endl;delete p;};
您在声明 p2
时遇到的问题是 lambda 的类型不是 default constructible。因此,指针类型的每个声明都需要将删除器的实例传递给它。
您可以通过将 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)lambda 也不是 CopyAssignable。我在上面发布的仿函数方法解决了这两个问题。
这里有两个错误(如错误消息所示):您不能复制分配 lambda(在 p1
的构造中需要),并且您不能默认构造 lambda(在 p1
的构造中需要) 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 实例,您可以 return 从函数中使用它,使用 std::function
或编写仿函数结构(参见其他答案)。
您收到的错误是因为 lambda 不可默认构造。当您声明 p2
时,您没有传递用作删除器的参数,因此编译器会抱怨无法默认构造它。
答案已经涵盖了使用自定义删除器的简洁方法。但是如果你必须对相同 class 的对象使用不同的删除器,你要么必须在构造每个智能指针时传递一个删除器,要么使用可默认构造的类型,以便 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);
}
这样,当没有管理对象时,您不仅不必分配删除器,而且还可以定义和使用其他删除器,这些删除器始终随创建它们的对象一起移动。
如果我使用自定义删除器制作 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.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.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.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.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.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:d\C++CodeProject\Hello\main.cpp|10|required from here|
C:\Program Files (x86)\CodeBlocks\MinGW\lib\gcc\mingw32.1.0\include\c++\tuple|59|error: use of deleted function '<lambda(int*)>::<lambda>()'|
F:d\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.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:d\C++CodeProject\Hello\main.cpp|11|required from here|
C:\Program Files (x86)\CodeBlocks\MinGW\lib\gcc\mingw32.1.0\include\c++\bits\unique_ptr.h|252|error: use of deleted function '<lambda(int*)>&<lambda(int*)>::operator=(const<lambda(int*)>&)'|
F:d\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)) ===|
您收到一条错误消息,因为在这种情况下 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));
}
两个问题。
- 在 C++20 之前 lambda 闭包类型不是 DefaultConstructible;这导致
std::unique_ptr
将其用作删除器而不是 DefaultConstructible。
Closure types are not DefaultConstructible. Closure types have
a deleted (until C++14)
no (since C++14)
default constructor. (until C++20)If no captures are specified, the closure type has a defaulted default constructor. Otherwise, it has no default constructor (this includes the case when there is a capture-default, even if it does not actually capture anything). (since C++20)
- C++20 之前的 lambda 闭包类型不可复制;这导致
std::unique_ptr
也将其用作删除器而不是 CopyAssignable。
The copy assignment operator is defined as deleted (and the move assignment operator is not declared). Closure types are not CopyAssignable. (until C++20)
If no captures are specified, the closure type has a defaulted copy assignment operator and a defaulted move assignment operator. Otherwise, it has a deleted copy assignment operator (this includes the case when there is a capture-default, even if it does not actually capture anything). (since C++20)
这意味着,您的代码自 C++20 起即可运行,因为 lambda 未指定捕获。在此之前,您可以使用 std::function
代替;例如std::function<void(int*)> del = [](int *p) { cout <<"obj deleted "<<endl;delete p;};
您在声明 p2
时遇到的问题是 lambda 的类型不是 default constructible。因此,指针类型的每个声明都需要将删除器的实例传递给它。
您可以通过将 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)lambda 也不是 CopyAssignable。我在上面发布的仿函数方法解决了这两个问题。
这里有两个错误(如错误消息所示):您不能复制分配 lambda(在 p1
的构造中需要),并且您不能默认构造 lambda(在 p1
的构造中需要) 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 实例,您可以 return 从函数中使用它,使用 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);
}
这样,当没有管理对象时,您不仅不必分配删除器,而且还可以定义和使用其他删除器,这些删除器始终随创建它们的对象一起移动。