Why allow shared_ptr<T[N]>?

喜你入骨 提交于 2019-12-05 09:46:43

问题


This answer cites N4082, which shows that the upcoming changes to std::shared_ptr will allow both T[] and T[N] variants:

Unlike the unique_ptr partial specialization for arrays, both shared_ptr<T[]> and shared_ptr<T[N]> will be valid and both will result in delete[] being called on the managed array of objects.

 template<class Y> explicit shared_ptr(Y* p);

Requires: Y shall be a complete type. The expression delete[] p, when T is an array type, or delete p, when T is not an array type, shall be well-formed, shall have well defined behavior, and shall not throw exceptions. When T is U[N], Y(*)[N] shall be convertible to T*; when T is U[], Y(*)[] shall be convertible to T*; otherwise, Y* shall be convertible to T*.

Unless I'm mistaken, a Y(*)[N] could only be formed by taking the address of an array, which clearly can't be owned or deleted by a shared_ptr. I also don't see any indication that N is used in any way to enforce the size of the managed object.

What is the motivation behind allowing the T[N] syntax? Does it yield any actual benefit, and if so, how is it used?


回答1:


You can get a pointer to a nested object sharing ownership with a std::shared_ptr to the containing object. If this nested object happens to be an array and you want to access it as an array type, you actually need to use T[N] with suitable T and N:

#include <functional>
#include <iostream>
#include <iterator>
#include <memory>
#include <queue>
#include <utility>
#include <vector>

using queue = std::queue<std::function<void()>>;

template <typename T>
struct is_range {
    template <typename R> static std::false_type test(R*, ...);
    template <typename R> static std::true_type test(R* r, decltype(std::begin(*r))*);
    static constexpr bool value = decltype(test(std::declval<T*>(), nullptr))();
};

template <typename T>
std::enable_if_t<!is_range<T>::value> process(T const& value) {
    std::cout << "value=" << value << "\n";
}

template <typename T>
std::enable_if_t<is_range<T>::value> process(T const &range) {
    std::cout << "range=[";
    auto it(std::begin(range)), e(std::end(range));
    if (it != e) {
        std::cout << *it;
        while  (++it != e) {
            std::cout << ", " << *it;
        }
    }
    std::cout << "]\n";
}

template <typename P, typename T>
std::function<void()> make_fun(P const& p, T& value) {
    return [ptr = std::shared_ptr<T>(p, &value)]{ process(*ptr); };
                            // here ----^
}

template <typename T, typename... M>
void enqueue(queue& q, std::shared_ptr<T> const& ptr, M... members) {
    (void)std::initializer_list<bool>{
        (q.push(make_fun(ptr, (*ptr).*members)), true)...
        };
}

struct foo {
    template <typename... T>
    foo(int v, T... a): value(v), array{ a... } {}
    int value;
    int array[3];
    std::vector<int> vector;
};

int main() {
    queue q;
    auto ptr = std::make_shared<foo>(1, 2, 3, 4);
    enqueue(q, ptr, &foo::value, &foo::array, &foo::vector);
    while (!q.empty()) {
        q.front()();
        q.pop();
    }
}

In the above code q is just a simple std::queue<std::function<void()>> but I hope you can imagine that it could be a thread-pool off-loading the processing to another thread. The actually scheduled processing is also trivial but, again, I hope you can imagine that it is actually some substantial amount of work.




回答2:


Unless I'm mistaken, a Y(*)[N] could only be formed by taking the address of an array, which clearly can't be owned or deleted by a shared_ptr.

Don't forget that shared_ptr is a generic resource management utility and can be constructed with a custom deallocator:

template<class Y, class D> shared_ptr(Y* p, D d);

Such a user-provided deallocator can perform an action other than delete/delete[]. For example if the the array under question is an array of file descriptors, the "deallocator" can just close all of them.

In such cases the shared_ptr doesn't own the object in the widely used sense and therefore can be bound to an existing array by taking its address.



来源:https://stackoverflow.com/questions/40447401/why-allow-shared-ptrtn

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!