从 unique_ptr<T[]> 初始化 shared_ptr<T>
Initialization of shared_ptr<T> from unique_ptr<T[]>
[ 问题的跟进]
我最近一直在处理指向 c-style 数组的智能指针。我最终完成了推荐的事情并改为使用指向向量的智能指针,但在那段时间里,我得到了一些建议:不要使用 shared_ptr<T>
object 来管理最初由make_unique<T[]>
因为它不会调用 delete[]
而是 delete
。
这对我来说似乎不合逻辑,我检查了 Coliru 和标准:
此代码:
#include <iostream>
#include <memory>
int main()
{
std::cout << "start!\n";
auto customArrayAllocator = [](unsigned int num){
std::cout << "custom array allocator\n";
return new int[num];
};
std::cout << "allocator constructed\n";
auto customArrayDeleter = [](int *ptr){
std::cout << "custom array deleter\n";
delete[] ptr;
};
std::cout << "deleter constructed\n";
std::unique_ptr<int[], decltype(customArrayDeleter)>
myUnique(customArrayAllocator(4), customArrayDeleter);
std::cout << "unique_ptr constructed\n";
std::shared_ptr<int>
myShared = std::move(myUnique);
std::cout << "shared_ptr constructed\n";
}
产生这个输出:
start!
allocator constructed
deleter constructed
custom array allocator
unique_ptr constructed
shared_ptr constructed
custom array deleter
这似乎表明 unique_ptr<T[]>
的删除器已传递给 shared_ptr<T>
,如我所料。
来自 C++14 标准 § 20.8.2.2.1 pg. 571 of doc, 585 of pdf
template shared_ptr(unique_ptr&& r);
Remark: This constructor shall not participate in overload resolution unless unique_ptr::pointer
is convertible to T*.
Effects: Equivalent to shared_ptr(r.release(), r.get_deleter()) when D is not a reference type,
otherwise shared_ptr(r.release(), ref(r.get_deleter())).
Exception safety: If an exception is thrown, the constructor has no effect.
如果我没看错,这意味着 shared_ptr
object 从 unique_ptr
的指针和删除器构造自身。此外,我的理解(从对原始问题的回答) unique_ptr<T[]>
的 ::pointer
类型是 T*
,应该可以转换为 shared_ptr<T>::pointer
的 [=28] =].所以删除器应该直接从 unique_ptr
object 复制,对吧?
我的测试之所以有效,是因为它实际上并不等同于 std::make_shared<T[]>
的功能,还是语法
std::shared_ptr<T> mySharedArray = std::make_unique<T[]>(16);
的一个很好的、异常安全的(和更清洁的)替代品
std::shared_ptr<T> mysharedArray(new T[16], [](T* ptr){delete[] ptr;});
及其同类,当我无法使用 Boost 的 shared array 并希望避免在我的代码中包含 vector
或 array
header 时?
是的,您的示例是有效的,原因与您陈述的完全相同。 unique_ptr::pointer
是 int *
,而您正试图将其所有权传递给 shared_ptr<int>
,因此您列出的转换构造函数将参与重载决议,并将复制删除器 (std::default_delete<int[]>
),因为它不是引用类型。
所以下面是有效的,当 shared_ptr
引用计数变为零时将调用 delete[]
std::shared_ptr<T> mySharedArray = std::make_unique<T[]>(16);
除了您显示的 lambda 之外,另一种写法是
std::shared_ptr<T> mySharedArray(new T[16], std::default_delete<int[]>());
这将导致 mySharedArray
获取与上一行相同的删除器。
[
我最近一直在处理指向 c-style 数组的智能指针。我最终完成了推荐的事情并改为使用指向向量的智能指针,但在那段时间里,我得到了一些建议:不要使用 shared_ptr<T>
object 来管理最初由make_unique<T[]>
因为它不会调用 delete[]
而是 delete
。
这对我来说似乎不合逻辑,我检查了 Coliru 和标准:
此代码:
#include <iostream>
#include <memory>
int main()
{
std::cout << "start!\n";
auto customArrayAllocator = [](unsigned int num){
std::cout << "custom array allocator\n";
return new int[num];
};
std::cout << "allocator constructed\n";
auto customArrayDeleter = [](int *ptr){
std::cout << "custom array deleter\n";
delete[] ptr;
};
std::cout << "deleter constructed\n";
std::unique_ptr<int[], decltype(customArrayDeleter)>
myUnique(customArrayAllocator(4), customArrayDeleter);
std::cout << "unique_ptr constructed\n";
std::shared_ptr<int>
myShared = std::move(myUnique);
std::cout << "shared_ptr constructed\n";
}
产生这个输出:
start!
allocator constructed
deleter constructed
custom array allocator
unique_ptr constructed
shared_ptr constructed
custom array deleter
这似乎表明 unique_ptr<T[]>
的删除器已传递给 shared_ptr<T>
,如我所料。
来自 C++14 标准 § 20.8.2.2.1 pg. 571 of doc, 585 of pdf
template shared_ptr(unique_ptr&& r);
Remark: This constructor shall not participate in overload resolution unless unique_ptr::pointer is convertible to T*.
Effects: Equivalent to shared_ptr(r.release(), r.get_deleter()) when D is not a reference type, otherwise shared_ptr(r.release(), ref(r.get_deleter())).
Exception safety: If an exception is thrown, the constructor has no effect.
如果我没看错,这意味着 shared_ptr
object 从 unique_ptr
的指针和删除器构造自身。此外,我的理解(从对原始问题的回答) unique_ptr<T[]>
的 ::pointer
类型是 T*
,应该可以转换为 shared_ptr<T>::pointer
的 [=28] =].所以删除器应该直接从 unique_ptr
object 复制,对吧?
我的测试之所以有效,是因为它实际上并不等同于 std::make_shared<T[]>
的功能,还是语法
std::shared_ptr<T> mySharedArray = std::make_unique<T[]>(16);
的一个很好的、异常安全的(和更清洁的)替代品
std::shared_ptr<T> mysharedArray(new T[16], [](T* ptr){delete[] ptr;});
及其同类,当我无法使用 Boost 的 shared array 并希望避免在我的代码中包含 vector
或 array
header 时?
是的,您的示例是有效的,原因与您陈述的完全相同。 unique_ptr::pointer
是 int *
,而您正试图将其所有权传递给 shared_ptr<int>
,因此您列出的转换构造函数将参与重载决议,并将复制删除器 (std::default_delete<int[]>
),因为它不是引用类型。
所以下面是有效的,当 shared_ptr
引用计数变为零时将调用 delete[]
std::shared_ptr<T> mySharedArray = std::make_unique<T[]>(16);
除了您显示的 lambda 之外,另一种写法是
std::shared_ptr<T> mySharedArray(new T[16], std::default_delete<int[]>());
这将导致 mySharedArray
获取与上一行相同的删除器。