¿Hay algún uso para unique_ptr con matriz?

12 minutos de lectura

¿Hay algun uso para unique ptr con matriz
pantano

std::unique_ptr tiene soporte para arreglos, por ejemplo:

std::unique_ptr<int[]> p(new int[10]);

pero es necesario? probablemente sea más conveniente usar std::vector o std::array.

¿Encuentras algún uso para esa construcción?

  • Para completar, debo señalar que no hay std::shared_ptr<T[]>, pero debería haberlo, y probablemente lo habrá en C++14 si alguien se molesta en redactar una propuesta. Mientras tanto, siempre hay boost::shared_array.

    – Seudónimo

    30 de mayo de 2013 a las 0:23

  • std::shared_ptr está en c++17 ahora.

    – Chen Li

    1 de noviembre de 2018 a las 2:04

  • Puede encontrar múltiples formas de hacer cualquier cosa en una computadora. Esta construcción tiene uso, especialmente en una ruta activa, porque erradica la sobrecarga de las operaciones de contenedores si sabe exactamente cómo apuntar a su matriz. Además, crea matrices de caracteres sin ninguna duda de almacenamiento contiguo.

    – kevr

    19 de abril de 2020 a las 17:13


  • Encontré esto útil para interoperar con estructuras C donde un miembro de la estructura determina su tamaño. Quiero que la memoria se desasigne automáticamente, pero no hay ningún tipo del tamaño adecuado para la desasignación, así que utilicé una matriz de caracteres.

    – Fuzzy Tew

    5 de julio de 2020 a las 17:08

  • Un detalle importante es que si std::unique_ptr<T[]> se utiliza, también se debe proporcionar un eliminador personalizado, ya que, de forma predeterminada, el puntero inteligente solo llama deletey no delete[]. Ver es.cppreference.com/w/cpp/memory/unique_ptr/unique_ptr

    – David Toth

    hace 2 días

¿Hay algun uso para unique ptr con matriz
Nicolás Bolas

Algunas personas no pueden darse el lujo de usar std::vector, incluso con asignadores. Algunas personas necesitan una matriz de tamaño dinámico, por lo que std::array Está fuera. Y algunas personas obtienen sus matrices de otro código que se sabe que devuelve una matriz; y ese código no se va a reescribir para devolver un vector o algo.

Al permitir unique_ptr<T[]>usted atiende esas necesidades.

En resumen, usas unique_ptr<T[]> Cuando usted necesitar para. Cuando las alternativas simplemente no van a funcionar para usted. Es una herramienta de último recurso.

  • @NoSenseEtAl: No estoy seguro de qué parte de “algunas personas no pueden hacer eso” se te escapa. Algunos proyectos tienen requisitos muy específicos, y entre ellos puede estar “no puedes usar vector“. Puede argumentar si esos son requisitos razonables o no, pero no puede negar que existe.

    – Nicolás Bolas

    30 de mayo de 2013 a las 15:48


  • No hay ninguna razón en el mundo por la que alguien no pueda usar std::vector si pueden usar std::unique_ptr.

    – Ruta Millas

    29 de abril de 2014 a las 14:48

  • aquí hay una razón para no usar vector: sizeof(std::vector) == 24; sizeof(std::unique_ptr) == 8

    – Arvid

    12/09/2014 a las 22:34

  • @DanNissenbaum Estos proyectos existen. Algunas industrias que están bajo un escrutinio muy estricto, como por ejemplo, la aviación o la defensa, la biblioteca estándar está fuera de los límites porque es difícil verificar y demostrar que es correcta para cualquier organismo rector que establezca las regulaciones. Puede argumentar que la biblioteca estándar está bien probada y estaría de acuerdo con usted, pero usted y yo no hacemos las reglas.

    – Emilio L.

    18/09/2014 a las 13:37

  • @DanNissenbaum Además, algunos sistemas duros en tiempo real no pueden usar la asignación de memoria dinámica en absoluto, ya que la demora que causa una llamada al sistema podría no estar teóricamente limitada y no puede probar el comportamiento en tiempo real del programa. O el límite puede ser demasiado grande, lo que supera su límite de WCET. Aunque no es aplicable aquí, ya que no usarían unique_ptr tampoco, pero ese tipo de proyectos realmente existen.

    – Emilio L.

    18/09/2014 a las 13:42

1646964617 355 ¿Hay algun uso para unique ptr con matriz
Seudónimo

Hay compensaciones, y usted elige la solución que coincida con lo que desea. La parte superior de mi cabeza:

Tamaño inicial

  • vector y unique_ptr<T[]> permitir que el tamaño se especifique en tiempo de ejecución
  • array solo permite especificar el tamaño en tiempo de compilación

Cambiar el tamaño

  • array y unique_ptr<T[]> no permitir cambiar el tamaño
  • vector lo hace

Almacenamiento

  • vector y unique_ptr<T[]> almacenar los datos fuera del objeto (típicamente en el montón)
  • array almacena los datos directamente en el objeto

Proceso de copiar

  • array y vector permitir copiar
  • unique_ptr<T[]> no permite copiar

intercambiar/mover

  • vector y unique_ptr<T[]> tener O(1) tiempo swap y mover operaciones
  • array tiene tiempo O(n) swap y mover operaciones, donde n es el número de elementos en la matriz

Invalidación de puntero/referencia/iterador

  • array garantiza que los punteros, las referencias y los iteradores nunca se invalidarán mientras el objeto esté activo, incluso en swap()
  • unique_ptr<T[]> no tiene iteradores; punteros y referencias sólo son invalidados por swap() mientras el objeto está activo. (Después del intercambio, los punteros apuntan a la matriz con la que intercambió, por lo que aún son “válidos” en ese sentido).
  • vector puede invalidar punteros, referencias e iteradores en cualquier reasignación (y proporciona algunas garantías de que la reasignación solo puede ocurrir en ciertas operaciones).

Compatibilidad con conceptos y algoritmos

  • array y vector ambos son contenedores
  • unique_ptr<T[]> no es un contenedor

Debo admitir que esto parece una oportunidad para refactorizar con un diseño basado en políticas.

  • No estoy seguro de entender lo que quieres decir en el contexto de invalidación de puntero. ¿Se trata de punteros a los objetos mismos o punteros a los elementos? ¿O algo mas? ¿Qué tipo de garantía obtiene de una matriz que no obtiene de un vector?

    – jogojapan

    29 de mayo de 2013 a las 2:52

  • Suponga que tiene un iterador, un puntero o una referencia a un elemento de un vector. Luego aumenta el tamaño o la capacidad de ese vector tal que fuerza una reasignación. Entonces ese iterador, puntero o referencia ya no apunta a ese elemento del vector. Esto es lo que entendemos por “invalidación”. Este problema no le pasa a array, porque no hay “reasignación”. En realidad, acabo de notar un detalle con eso, y lo he editado para adaptarlo.

    – Seudónimo

    29 de mayo de 2013 a las 3:33


  • Ok, no puede haber invalidación como resultado de la reasignación en una matriz o unique_ptr<T[]> porque no hay reasignación. Pero, por supuesto, cuando la matriz queda fuera del alcance, los punteros a elementos específicos seguirán siendo invalidados.

    – jogojapan

    29 de mayo de 2013 a las 3:38

  • @rubenvb Claro que puede, pero no puede (decir) usar bucles for basados ​​​​en rango directamente. Por cierto, a diferencia de un normal T[]el tamaño (o información equivalente) debe estar dando vueltas en algún lugar para operator delete[] para destruir correctamente los elementos de la matriz. Sería bueno si el programador tuviera acceso a eso.

    – Seudónimo

    30 de mayo de 2013 a las 0:09


  • @Aidiakapi C++ requiere que si delete[] una matriz de objetos que tienen destructores, los destructores se ejecutan. Por esa razón, el tiempo de ejecución de C++ ya necesita conocer el tamaño real de la mayoría de las matrices que se han asignado de esa manera. Ahora, las implementaciones decentes de C++ optimizan los destructores si los objetos en la matriz no tienen destructor (por ejemplo, un tipo básico) o un destructor que no hace nada. Sin embargo, normalmente no optimizan el asignador de memoria para este caso. Podría pasar, pero no pasa. Así que la información del tamaño está ahí.

    – Seudónimo

    28 de mayo de 2015 a las 2:31


¿Hay algun uso para unique ptr con matriz
Carlos Salvia

Una de las razones por las que podría usar un unique_ptr es si no quiere pagar el costo del tiempo de ejecución de inicialización de valor la matriz

std::vector<char> vec(1000000); // allocates AND value-initializes 1000000 chars

std::unique_ptr<char[]> p(new char[1000000]); // allocates storage for 1000000 chars

los std::vector constructor y std::vector::resize() inicializará el valor T – pero new no hare eso si T es un POD.

Consulte Objetos inicializados por valor en C++ 11 y constructor std::vector

Tenga en cuenta que vector::reserve no es una alternativa aquí: ¿Es seguro acceder al puntero sin formato después de std::vector::reserve?

Es la misma razón por la que un programador de C podría elegir malloc sobre calloc.

  • Pero esta razón no es la única solución.

    – Ruslán

    23 de agosto de 2016 a las 13:33

  • @Ruslan En la solución vinculada, los elementos de la matriz dinámica todavía tienen un valor inicializado, pero la inicialización del valor no hace nada. Estoy de acuerdo en que un optimizador que no se da cuenta de que no hacer nada 1000000 veces puede implementarse sin código no vale un centavo, pero uno podría preferir no depender de esta optimización en absoluto.

    –Marc van Leeuwen

    25/03/2017 a las 13:30

  • otra posibilidad más es proporcionar a std::vector un asignador personalizado que evita la construcción de tipos que son std::is_trivially_default_constructible y destrucción de objetos que son std::is_trivially_destructibleaunque estrictamente esto viola el estándar C++ (ya que tales tipos no se inicializan por defecto).

    – Gualterio

    25 mayo 2017 a las 21:37


  • también std::unique_ptr no proporciona ninguna comprobación vinculada, al contrario de muchos std::vector implementaciones.

    – diapiro

    26 de diciembre de 2017 a las 17:09


  • @diapir No se trata de la implementación: std::vector es requerido por el estándar para comprobar los límites en .at(). Supongo que quiso decir que algunas implementaciones tienen modos de depuración que se registrarán .operator[] también, pero considero que es inútil para escribir un buen código portátil.

    – subrayado_d

    26 de junio de 2020 a las 8:26

1646964618 746 ¿Hay algun uso para unique ptr con matriz
Andy merodea

Un std::vector se puede copiar, mientras que unique_ptr<int[]> permite expresar la propiedad única de la matriz. std::arraypor otro lado, requiere que el tamaño se determine en tiempo de compilación, lo que puede ser imposible en algunas situaciones.

1646964619 559 ¿Hay algun uso para unique ptr con matriz
novato

Scott Meyers tiene esto que decir en Eficaz Modern C++

La existencia de std::unique_ptr porque las matrices deberían ser solo de interés intelectual para usted, porque std::array,
std::vector, std::string son prácticamente siempre mejores opciones de estructura de datos que las matrices sin formato. Acerca de la única situación que puedo concebir cuando un std::unique_ptr<T[]> tendría sentido sería cuando está utilizando una API similar a C que devuelve un puntero sin procesar a una matriz de montón de la que asume la propiedad.

Sin embargo, creo que la respuesta de Charles Salvia es relevante: que std::unique_ptr<T[]> es la única forma de inicializar una matriz vacía cuyo tamaño no se conoce en tiempo de compilación. ¿Qué diría Scott Meyers sobre esta motivación para usar std::unique_ptr<T[]>?

  • Parece que simplemente no imaginó algunos casos de uso, a saber, un búfer cuyo tamaño es fijo pero desconocido en el momento de la compilación, y/o un búfer para el que no permitimos copias. También existe la eficiencia como una posible razón para preferirlo a vector stackoverflow.com/a/24852984/2436175.

    – Antonio

    17/07/2018 a las 21:43


1646964620 815 ¿Hay algun uso para unique ptr con matriz
Jorge

Contrariamente a std::vector y std::array, std::unique_ptr puede poseer un puntero NULL.
Esto es útil cuando se trabaja con API de C que esperan una matriz o NULL:

void legacy_func(const int *array_or_null);

void some_func() {    
    std::unique_ptr<int[]> ptr;
    if (some_condition) {
        ptr.reset(new int[10]);
    }

    legacy_func(ptr.get());
}

  • Parece que simplemente no imaginó algunos casos de uso, a saber, un búfer cuyo tamaño es fijo pero desconocido en el momento de la compilación, y/o un búfer para el que no permitimos copias. También existe la eficiencia como una posible razón para preferirlo a vector stackoverflow.com/a/24852984/2436175.

    – Antonio

    17/07/2018 a las 21:43


No puedo estar en desacuerdo con el espíritu de la respuesta aceptada lo suficiente. ¿”Una herramienta de último recurso”? ¡Lejos de ahi!

A mi modo de ver, una de las características más sólidas de C++ en comparación con C y otros lenguajes similares es la capacidad de expresar restricciones para que se puedan verificar en el momento de la compilación y se pueda evitar el mal uso accidental. Entonces, cuando diseñe una estructura, pregúntese qué operaciones debe permitir. Todos los demás usos deben estar prohibidos, y es mejor si tales restricciones se pueden implementar de forma estática (en tiempo de compilación) para que el mal uso resulte en una falla de compilación.

Entonces, cuando se necesita una matriz, las respuestas a las siguientes preguntas especifican su comportamiento: 1. ¿Su tamaño es a) dinámico en tiempo de ejecución, o b) estático, pero solo conocido en tiempo de ejecución, o c) estático y conocido en tiempo de compilación? 2. ¿Se puede asignar la matriz en la pila o no?

Y según las respuestas, esto es lo que veo como la mejor estructura de datos para una matriz de este tipo:

       Dynamic     |   Runtime static   |         Static
Stack std::vector      unique_ptr<T[]>          std::array
Heap  std::vector      unique_ptr<T[]>     unique_ptr<std::array>

si, creo unique_ptr<std::array> también debe considerarse, y tampoco es una herramienta de último recurso. Piensa qué encaja mejor con tu algoritmo.

Todos estos son compatibles con las API de C simples a través del puntero sin procesar a la matriz de datos (vector.data() / array.data() / uniquePtr.get()).

PD Además de las consideraciones anteriores, también hay una de propiedad: std::array y std::vector tienen semántica de valor (tienen soporte nativo para copiar y pasar por valor), mientras que unique_ptr<T[]> solo se puede mover (hace cumplir la propiedad única). Cualquiera de los dos puede ser útil en diferentes escenarios. Por el contrario, los arreglos estáticos simples (int[N]) y matrices dinámicas simples (new int[10]) no ofrecen ninguno y, por lo tanto, deben evitarse si es posible, lo que debería ser posible en la gran mayoría de los casos. Si eso no fuera suficiente, las matrices dinámicas simples tampoco ofrecen ninguna forma de consultar su tamaño: una oportunidad adicional para la corrupción de la memoria y los agujeros de seguridad.

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad