vectores sirven que punteros puntero para matrices los funciones ejemplo dev declaracion con aritmetica apuntadores c++ api pointers smart-pointers

sirven - ¿Por qué las bibliotecas y frameworks C++ nunca usan punteros inteligentes?



punteros y vectores en c (8)

Leí en algunos artículos que los punteros crudos casi nunca deberían usarse. En su lugar, siempre deben incluirse en punteros inteligentes, ya sean punteros compartidos o de alcance.

Sin embargo, noté que los frameworks como Qt, wxWidgets y bibliotecas como Boost nunca regresan ni esperan punteros inteligentes, como si no los estuvieran usando en absoluto. En cambio, regresan o esperan punteros crudos. ¿Hay alguna razón para eso? ¿Debo mantenerme alejado de los indicadores inteligentes cuando escribo una API pública, y por qué?

Me pregunto por qué se recomiendan los indicadores inteligentes cuando muchos proyectos importantes parecen evitarlos.


Además del hecho de que muchas bibliotecas fueron escritas antes de la llegada de los punteros inteligentes estándar, la razón principal es probablemente la falta de una interfaz binaria de aplicación estándar de C ++ (ABI).

Si está escribiendo una biblioteca de solo encabezado, puede pasar punteros inteligentes y contenedores estándar al contenido de su corazón. Su fuente está disponible para su biblioteca en tiempo de compilación, por lo que confía solo en la estabilidad de sus interfaces, no en sus implementaciones.

Pero debido a la falta de ABI estándar, generalmente no puede pasar estos objetos de forma segura a través de los límites del módulo. Un GCC shared_ptr es probablemente diferente de un shared_ptr , que también puede diferir de un Intel shared_ptr . Incluso con el mismo compilador, no se garantiza que estas clases sean binarias compatibles entre versiones.

La conclusión es que si desea distribuir una versión preconstruida de su biblioteca, necesita un ABI estándar en el que confiar. C no tiene uno, pero los proveedores de compiladores son muy buenos acerca de la interoperabilidad entre bibliotecas C para una plataforma determinada; existen estándares de facto.

La situación no es tan buena para C ++. Los compiladores individuales pueden manejar la interoperación entre sus propios binarios, por lo que tiene la opción de distribuir una versión para cada compilador compatible, a menudo GCC y MSVC. Pero a la luz de esto, la mayoría de las bibliotecas solo exportan una interfaz C, y eso significa punteros crudos.

Sin embargo, el código que no es de biblioteca debería, en general, preferir los punteros inteligentes sobre los crudos.


Buena pregunta. No conozco los artículos específicos a los que me refieres, pero he leído cosas similares de vez en cuando. Mi sospecha es que los escritores de tales artículos tienden a albergar un sesgo en contra de la programación al estilo de C ++. Si el escritor programa en C ++ solo cuando debe, luego regresa a Java o lo antes que pueda, entonces realmente no comparte la mentalidad de C ++.

Uno sospecha que algunos o la mayoría de los mismos escritores prefieren los administradores de memoria recolectores de basura. No lo hago, pero pienso de manera diferente a como lo hacen.

Los indicadores inteligentes son geniales, pero tienen que mantener el recuento de referencias. El mantenimiento de los recuentos de referencia conlleva costos, a menudo modestos, pero de todos modos costos, en tiempo de ejecución. No hay nada de malo en ahorrar estos costos usando punteros simples, especialmente si los punteros son administrados por destructores.

Una de las cosas excelentes de C ++ es su compatibilidad con la programación de sistemas integrados. El uso de punteros descubiertos es parte de eso.

Actualización: un comentarista ha observado correctamente que el nuevo unique_ptr C ++ (disponible desde TR1) no cuenta las referencias. El comentarista también tiene una definición diferente de "puntero inteligente" de la que tengo en mente. Él puede tener razón sobre la definición.

Actualización adicional: el hilo de comentarios a continuación es esclarecedor. Todo es una lectura recomendada.


Hay dos problemas con los punteros inteligentes (anteriores a C ++ 11):

  • no estándares, por lo que cada biblioteca tiende a reinventar la suya (problemas de dependencias y síndromes NIH)
  • costo potencial

El puntero inteligente predeterminado , en el sentido de que no tiene costo, es unique_ptr . Desafortunadamente requiere la semántica del movimiento C ++ 11, que solo apareció recientemente. Todos los demás punteros inteligentes tienen un costo ( shared_ptr , intrusive_ptr ) o tienen una semántica menos que ideal ( auto_ptr ).

Con C ++ 11 a la vuelta de la esquina, trayendo un std::unique_ptr , uno estaría tentado a pensar que finalmente ha terminado ... No soy tan optimista.

Solo unos pocos compiladores importantes implementan la mayor parte de C ++ 11, y solo en sus versiones recientes. Podemos esperar que las principales bibliotecas, como QT y Boost, estén dispuestas a mantener la compatibilidad con C ++ 03 por un tiempo, lo que de alguna manera imposibilita la amplia adopción de los nuevos e inteligentes punteros inteligentes.


No debe alejarse de los punteros inteligentes, tienen su uso especialmente en aplicaciones donde tiene que pasar un objeto.

Las bibliotecas tienden a devolver un valor o rellenar un objeto. Por lo general, no tienen objetos que deban usarse en muchos lugares, por lo que no es necesario que utilicen punteros inteligentes (al menos no en su interfaz, pueden usarlos internamente).

Podría tomar como ejemplo una biblioteca en la que hemos estado trabajando, donde después de algunos meses de desarrollo me di cuenta de que solo usábamos punteros y punteros inteligentes en unas pocas clases (3-5% de todas las clases).

Pasar variables por referencia fue suficiente en la mayoría de los lugares, usamos punteros inteligentes cada vez que teníamos un objeto que podría ser nulo, y punteros sin procesar cuando una biblioteca que utilizábamos nos obligaba a hacerlo.

Editar (no puedo comentar debido a mi reputación): pasar variables por referencia es muy flexible: si quieres que el objeto sea de solo lectura puedes usar una referencia constante (aún puedes hacer moldes desagradables para poder escribir el objeto) ) pero obtienes la máxima protección posible (es lo mismo con los punteros inteligentes). Pero estoy de acuerdo en que es mucho mejor devolver el objeto.


Puede haber muchas razones. Para enumerar algunos de ellos:

  1. Los punteros inteligentes se convirtieron en parte del estándar recientemente. Hasta entonces eran parte de otras bibliotecas
  2. Su uso principal es evitar fugas de memoria; muchas bibliotecas no tienen su propia administración de memoria; En general, proporcionan utilidades y API
  3. Se implementan como envoltura, ya que en realidad son objetos y no punteros. Que tiene un costo de tiempo / espacio adicional, en comparación con los punteros sin procesar; Los usuarios de las bibliotecas pueden no querer tener tales gastos generales

Editar : El uso de punteros inteligentes es una opción completamente del desarrollador. Depende de varios factores.

  1. En sistemas críticos para el rendimiento, es posible que no desee utilizar punteros inteligentes que generen gastos generales

  2. El proyecto que necesita compatibilidad con versiones anteriores, es posible que no desee utilizar punteros inteligentes que tengan características específicas de C ++ 11

Edit2 Hay una cadena de varios downvotes en el lapso de 24 horas debido al paso inferior. No entiendo por qué la respuesta es downvoted a pesar de que a continuación es solo una sugerencia complementaria y no una respuesta.
Sin embargo, C ++ siempre te facilita tener las opciones abiertas. :) p.ej

template<typename T> struct Pointer { #ifdef <Cpp11> typedef std::unique_ptr<T> type; #else typedef T* type; #endif };

Y en su código, utilícelo como:

Pointer<int>::type p;

Para aquellos que dicen que un puntero inteligente y un puntero sin procesar son diferentes, estoy de acuerdo con eso. El código anterior era solo una idea donde uno puede escribir un código que es intercambiable solo con un #define , esto no es compulsión ;

Por ejemplo, T* tiene que eliminarse explícitamente, pero un puntero inteligente no. Podemos tener un Destroy() plantilla Destroy() para manejar eso.

template<typename T> void Destroy (T* p) { delete p; } template<typename T> void Destroy (std::unique_ptr<T> p) { // do nothing }

y usarlo como:

Destroy(p);

De la misma manera, para un puntero sin formato podemos copiarlo directamente y para el puntero inteligente podemos usar una operación especial.

Pointer<X>::type p = new X; Pointer<X>::type p2(Assign(p));

Donde Assign() es como:

template<typename T> T* Assign (T *p) { return p; } template<typename T> ... Assign (SmartPointer<T> &p) { // use move sematics or whateve appropriate }


Qt inútilmente reinventó muchas partes de la biblioteca Standard en un intento por convertirse en Java. Creo que en realidad tiene sus propios indicadores inteligentes ahora, pero en general, no es un pináculo del diseño. wxWidgets, hasta donde yo sé, fue diseñado mucho antes de que se escribieran punteros inteligentes utilizables.

En cuanto a Boost, espero totalmente que utilicen punteros inteligentes cuando corresponda. Es posible que tengas que ser más específico.

Además, no olvide que existen indicadores inteligentes para hacer cumplir la propiedad. Si la API no tiene semántica de propiedad, ¿por qué usar un puntero inteligente?


También depende del dominio en el que trabajes. Escribo motores de juego para ganarme la vida, evitamos el impulso como la peste, en los juegos, la sobrecarga de impulso no es aceptable. En nuestro motor central terminamos escribiendo nuestra propia versión de stl (Like the ea stl).

Si tuviera que escribir una aplicación de formularios, podría considerar el uso de punteros inteligentes; pero una vez que la administración de la memoria es la segunda naturaleza, no tener control granular sobre la memoria se vuelve molesto.


También hay otros tipos de punteros inteligentes. Es posible que desee un puntero inteligente especializado para algo como la replicación de red (que detecta si se accede y envía modificaciones al servidor o algo así), mantiene un historial de cambios, marca el hecho de que se accedió para que pueda investigarse cuando guarda datos en el disco, etc. No estoy seguro de si hacer eso en el puntero es la mejor solución, pero el uso de los tipos de puntero inteligente incorporados en las bibliotecas podría provocar que las personas se vean atrapadas en ellos y pierdan flexibilidad.

Las personas pueden tener todo tipo de requisitos y soluciones de administración de memoria diferentes a los indicadores inteligentes. Es posible que desee administrar la memoria yo mismo, podría estar asignando espacio para cosas en un grupo de memoria para que se asigne de antemano y no en tiempo de ejecución (útil para juegos). Podría estar usando una implementación recogida de basura de C ++ (C ++ 11 lo hace posible aunque todavía no existe ninguno). O tal vez no estoy haciendo algo lo suficientemente avanzado como para preocuparme por molestarme con ellos, puedo saber que no me voy a olvidar de los objetos no inicializados y demás. Tal vez estoy seguro de mi capacidad para administrar la memoria sin la muleta del puntero.

La integración con C es otro problema también.

Otro problema es que los punteros inteligentes son parte del STL. C ++ está diseñado para ser utilizable sin el STL.