Why allow shared_ptr?

前端 未结 2 1031
渐次进展
渐次进展 2021-02-18 15:44

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

相关标签:
2条回答
  • 2021-02-18 16:07

    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.

    0 讨论(0)
  • 2021-02-18 16:07

    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.

    0 讨论(0)
提交回复
热议问题