简体   繁体   English

shared_ptr的初始化 <T> 来自unique_ptr <T[]>

[英]Initialization of shared_ptr<T> from unique_ptr<T[]>

[Followup to this question] [跟进这个问题]

I've been dealing a little bit with smart pointers to c-style arrays recently. 最近,我一直在处理一些关于c风格数组的智能指针。 I ultimately wound up doing the recommended thing and using smart pointers to vectors instead, but during that period, I got a bit of advice: don't use a shared_ptr<T> object to manage an array initially made with make_unique<T[]> because it won't call delete[] but rather delete . 我最终做了推荐的事情,并使用智能指针代替向量,但在此期间,我得到了一些建议:不要使用shared_ptr<T>对象来管理最初使用make_unique<T[]>的数组make_unique<T[]>因为它不会调用delete[]而是delete

This didn't seem logical to me, and I checked both Coliru and the Standard: 这对我来说似乎不合逻辑,我检查了Coliru和标准:


This code: 这段代码:

#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";
}

produces this output: 产生这个输出:

start!
allocator constructed
deleter constructed
custom array allocator
unique_ptr constructed
shared_ptr constructed
custom array deleter

Which seems to indicate that the unique_ptr<T[]> 's deleter is passed to the shared_ptr<T> , as I expected. 这似乎表明unique_ptr<T[]>的删除器被传递给shared_ptr<T> ,正如我预期的那样。


From the C++14 Standard § 20.8.2.2.1 pg. 来自C ++ 14标准§20.8.2.2.1pg 571 of doc, 585 of pdf doc的571,pdf的585

template shared_ptr(unique_ptr&& r); template shared_ptr(unique_ptr && r);
Remark : This constructor shall not participate in overload resolution unless unique_ptr::pointer is convertible to T*. 备注 :除非unique_ptr :: pointer可转换为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())). 效果 :当D不是引用类型时,等效于shared_ptr(r.release(),r.get_deleter()),否则为shared_ptr(r.release(),ref(r.get_deleter()))。
Exception safety : If an exception is thrown, the constructor has no effect. 异常安全 :如果抛出异常,则构造函数无效。

If I'm reading that right, it means that a shared_ptr object constructs itself from both the pointer and the deleter of a unique_ptr . 如果我正确读取它,则意味着shared_ptr对象从unique_ptr的指针和删除器构造自身。 Furthermore, it's my understanding (from the answer to the original question) that the ::pointer type of unique_ptr<T[]> is T* , which should be convertible to shared_ptr<T>::pointer 's T* . 此外,我的理解(从原始问题的答案), unique_ptr<T[]>::pointer类型是T* ,它应该可以转换为shared_ptr<T>::pointerT* So the deleter should just be copied right from the unique_ptr object, right? 所以删除器应该直接从unique_ptr对象复制,对吧?


Did my test only work because it's not actually equivalent to the function of std::make_shared<T[]> , or is the syntax 我的测试是否有效,因为它实际上并不等同于std::make_shared<T[]> ,或者是语法

std::shared_ptr<T> mySharedArray = std::make_unique<T[]>(16);

a good, exception safe (and cleaner) alternative to 一个好的,异常安全(和更清洁)的替代品

std::shared_ptr<T> mysharedArray(new T[16], [](T* ptr){delete[] ptr;});

and its ilk, when I am unable to use Boost's shared array and desire to avoid including either the vector or the array header with my code? 当我无法使用Boost的共享数组并且希望避免在我的代码中包含vectorarray头时,它的同类?

Yes, your example is valid for the very reasons you've stated. 是的,你的例子是有效的,因为你说的原因。 unique_ptr::pointer is int * , and you're trying to pass ownership of that to a shared_ptr<int> , so the converting constructor you've listed will participate in overload resolution, and will make a copy of the deleter ( std::default_delete<int[]> ) because it's not a reference type. unique_ptr::pointerint * ,你试图将它的所有权传递给shared_ptr<int> ,所以你列出的转换构造函数将参与重载解析,并将复制删除器( std::default_delete<int[]> )因为它不是引用类型。

So the following is valid, and will call delete[] when the shared_ptr reference count goes to zero 因此以下是有效的,并且当shared_ptr引用计数变为零时将调用delete[]

std::shared_ptr<T> mySharedArray = std::make_unique<T[]>(16);

Another way to write this, other than the lambda you've shown, is 除了你展示的lambda之外,另一种写这个的方法是

std::shared_ptr<T> mySharedArray(new T[16], std::default_delete<int[]>());

which will result in mySharedArray acquiring the same deleter as the previous line. 这将导致mySharedArray获取与前一行相同的删除器。

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

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