weak_ptr smart shared_ptr pointer example create c++ stl shared-ptr c++1z

c++ - smart - ¿Por qué permitir shared_ptr<T[N]>?



unique pointer (2)

Esta respuesta cita N4082 , que muestra que los próximos cambios en std::shared_ptr permitirán las variantes T[] y T[N] :

A diferencia de la especialización parcial unique_ptr para matrices, tanto shared_ptr<T[]> y shared_ptr<T[N]> serán válidas y ambas harán que se llame a delete[] en la matriz administrada de objetos.

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

Requiere : Y debe ser un tipo completo. La expresión delete[] p , cuando T es un tipo de matriz, o delete p , cuando T no es un tipo de matriz, debe estar bien formada, debe tener un comportamiento bien definido y no debe arrojar excepciones. Cuando T es U[N] , Y(*)[N] será convertible a T* ; cuando T es U[] , Y(*)[] será convertible a T* ; de lo contrario, Y* será convertible a T* .

A menos que me equivoque, una Y(*)[N] solo podría formarse tomando la dirección de una matriz, que claramente no puede ser propiedad o eliminada por un shared_ptr . Tampoco veo ninguna indicación de que N se use de ninguna forma para imponer el tamaño del objeto gestionado.

¿Cuál es la motivación detrás de permitir la sintaxis T[N] ? ¿Reparte algún beneficio real y, de ser así, cómo se usa?


A menos que me equivoque, una Y(*)[N] solo podría formarse tomando la dirección de una matriz, que claramente no puede ser propiedad o eliminada por un shared_ptr .

No olvide que shared_ptr es una utilidad de gestión de recursos genérica y puede construirse con un desglose personalizado:

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

Dicho desasignador proporcionado por el usuario puede realizar una acción que no sea delete / delete[] . Por ejemplo, si la matriz en cuestión es una matriz de descriptores de archivos, el "deallocator" puede cerrarlos todos.

En tales casos, shared_ptr no posee el objeto en el sentido ampliamente utilizado y, por lo tanto, puede vincularse a una matriz existente tomando su dirección.


Puede obtener un puntero a un objeto anidado que comparte la propiedad con std::shared_ptr para el objeto que lo contiene. Si este objeto anidado resulta ser una matriz y desea acceder a él como un tipo de matriz, realmente necesita usar T[N] con T y N adecuados:

#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(); } }

En el código anterior q solo hay una simple std::queue<std::function<void()>> pero espero que puedas imaginar que podría ser un grupo de subprocesos que descargue el procesamiento a otro subproceso. El procesamiento realmente programado también es trivial, pero, de nuevo, espero que puedas imaginar que en realidad es una cantidad sustancial de trabajo.