¿Cuáles son las deficiencias conocidas de const
en C++ y C++ 0x?¿Qué pasa con const?
Respuesta
Las dos cuestiones principales que he visto quejas frecuentes acerca de los grupos de noticias, son
La necesidad de perder mucho tiempo de compatibilidad con las API no compatibles con const (especialmente las de Microsoft).
El need to define both const and non-const version of a method.
Creo que este último podría/debería ser compatible con el idioma.
Posiblemente junto con la compatibilidad con las implementaciones de funciones de miembros covariantes, ya que ambas necesitan algún modo de detectar el tipo del puntero this
.
Un tercer problema es que
Saludos & HTH.,
¿Qué API de Microsoft no son compatibles con const? IIRC, la API de Windows usa LPCTSTR, MFC usa const IIRC, etc. No se me ocurre ninguna. – Rup
@Rup: necesitaría mucha investigación para todos. Estoy informando de qué se ha quejado la gente, pero puedo confirmarlo por mi propia experiencia. si hubiera solo algunas funciones problemáticas, tal vez recordaría nombres, pero todo ha terminado. –
@Rup: muchas API de Microsoft no usan mucha const. ¿Cuándo fue la última vez que viste una const HANDLE? O un const IDirect3DDevice9 *? Microsoft usa const para cadenas y eso es todo. – Puppy
El único malo de const
es que es seriamente subestimado por muchos desarrolladores. Es una de las mejores herramientas en la caja de herramientas de C++, muy nítida y, sin embargo, no es peligroso cortarse con ella.
"Pero lo que hizo que los que se habían reído de mí dejaran de reírse fue cuando, después de varios días, se hizo evidente que algunos errores muy difíciles de reproducir que algunos de mis compañeros de trabajo estaban buscando desesperadamente habían desaparecido". (de [chat] (http://chat.stackoverflow.com/transcript/message/254713#254713)) –
"issues"?
Si no va a modificar el valor de un puntero pasado (se usa simplemente para la entrada de referencia de una función), marque que es const
. Lo mismo si el valor de una variable en particular no cambiará después de su inicialización. Si una función es segura para invocar una instancia de clase const
, márquela también en const
. Cuantos más elementos estén correctamente anotados const
, es menos probable que cometas un error inadvertidamente y cuantas más optimizaciones el compilador teóricamente pueda realizar en ausencia de conocimiento completo (como cuando compilas con solo prototipos de funciones disponibles).
Las versiones modernas de gcc tienen soporte para advertencias cuando intentas convertir una variable const
en una no const
. Sugiero que dejes esas advertencias habilitadas.
Lo único a lo que hay que tener cuidado es exactamente qué está marcando const
; const char * foo()
no es lo mismo que char * foo() const
.
No estoy preguntando cómo usar const. Ya sé cómo usar const. Estaba buscando * problemas * con const. – Puppy
El problema con const es que los programadores que utilizan de forma incorrecta nuestra manera inconsistente
Un problema es que el idioma también le permite const_cast a la basura, lo que contradice el propósito de usar const en el primer lugar.
en realidad no lo puedes descartar explícitamente y obviamente necesitas poder const_cast para admitir API heredadas –
No es esto nuevo ... 'const' sería inútil ** sin ** la capacidad de descartarlo, porque en el código del mundo real, tiene que lidiar con las API escritas por programadores que no entienden la exactitud de la const (o en un tiempo en el que 'const' aún no formaba parte de C++). – fredoverflow
@FredOverflow Ya veo ... Nunca antes me había encontrado con esa situación. Gracias por la aclaración. – Dave
Lo que falla con const
es que muchos programadores no parecen ser capaces de entenderlo completamente, y un proyecto de "media const-correct" simplemente no funciona.Esto es lo que necesita saber:
Foo
vsconst Foo
(oFoo const
)Foo&
vsconst Foo&
(oFoo const&
)- referencias-a-const se unen a todo tipo de cosas, mientras referencias a la no-const no lo hacen
Foo*
vsconst Foo*
(oFoo const*
)- variables de puntero también pueden ser
Foo* const
yconst Foo* const
(oFoo const* const
)
- variables de puntero también pueden ser
void Foo::mutator()
vsint Foo::accessor() const
- pero los miembros del puntero dentro métodos constantes siguen apuntando a objetos no constante
- para que podamos accidentalmente devuelve datos no const desde una función const
iterator
vsconst_iterator
- variables de iterador también pueden ser
const iterator
yconst const_iterator
- variables de iterador también pueden ser
Migración a C++ de un lenguaje que no tiene un concepto const es bastante difícil, cualquier muchos no ven el punto.
Nit-picking: las referencias a los objetos no pueden ser const, pero las referencias pueden hacer referencia a los objetos const. (La mayoría de la gente sabe a qué te refieres, pero la distinción es más importante con los punteros, donde tenemos tanto punteros como punteros para const.) – Philipp
@Phil: Bien, cambié las partes relevantes de inglés a C++ ;-) – fredoverflow
Esa cantidad los programadores no entienden que no es un problema con 'const'. Es un problema con los programadores y el estado gravemente patético de la educación de programación en todo el mundo occidental. –
El problema principal es que tiene que escribirlo. Debe ser el valor predeterminado, y todas las variables o parámetros variables deben especificarse explícitamente.
No se puede votar lo suficiente. Aunque (o porque) causaría estragos en la mayoría de las ideas preconcebidas de los programadores. –
Hooray para variables F # :) – fredoverflow
Excepto por dos cosas: la mayoría de las variables se crean para escribirse. Hacer que todos lean solo de manera predeterminada crea más trabajo. También la filosofía del lenguaje C y C++ es que el programador sabe lo que está haciendo y que el lenguaje no debe impedirle hacer lo que quiera. – Jay
Una cosa que está "mal" es que no se puede convertir T ** a T const * const * que debe permitirse porque no es peligroso. No permitir que T ** se convierta a T const ** es correcto, esa conversión no es válida.
A veces he mencionado que const es en realidad una forma económica de "dividir" su interfaz en métodos de solo lectura y métodos de escritura. Probablemente sería poco práctico en C++. Sin embargo, sería más práctico en Java tener versiones de ReadOnly de colecciones, donde no tienen const y donde sus tipos de colección están más orientados a objetos.
const-ness no se propaga: El problema aquí es que si llevo mi clase, la constness no es "comprobada" por el compilador, es decir, mi clase de interfaz puede tener un método "const" llamar a un método non-const en el pImpl y el compilador no se quejará. Esto se debe a que lo único que mi método const está garantizado de no hacer es cambiar el puntero para apuntar a un objeto diferente, y mi pImpl nunca va a cambiar. Incluso podría ser un puntero const (no puntero a const).
La falta de adecuada covarianza entre shared_ptr<T>
y shared_ptr<const T>
podría ser un problema también, aunque en general he visto que no sea el problema, sino que los desarrolladores lo general typedef sus shared_ptrs y rara vez typedef la shared_ptr a const. Y a veces pasan const shared_ptr<T> &
y piensan que están pasando un puntero compartido a una const T (como con const T *) que no lo son.
"no se puede convertir' T ** 'a' T const * const * '" - esta parte es incorrecta (al menos con los compiladores que uso); recuerdo que fue una molestia en C pero C++ lo hizo bien. – anatolyg
puede tener const-checking para la clase pimpl, no es gran cosa ... por ejemplo, observe el uso de Qts de las clases de pimpl ... (usan 2 funciones privadas de pimpl-accessor (const/nonconst) para acceder al objeto pimpl, si quiero asegurarme de que no accedas al objeto pimpl sin usar estas funciones (y así eludir la comprobación de const), puedes usar un 'void *' completamente opaco para el objeto pimpl, y agregar algunos reinterpret_casts a las funciones del acessor (mira la implementación de, por ejemplo, Q_DECLARE_PRIVATE) – smerlin
@anatolyg: está en lo cierto. El primer párrafo no describe algo "incorrecto" con 'const' porque no es verdadero. Consulte 4.4 [conv.qual]/4 de ISO/IEC 14882: 2003. –
Una cosa es que todavía es posible subvertirlo. es decirtodavía es legal para hacer algo como esto:
void foo(const inst& x)
{
const_cast<int&> x = 3;
}
Incluso puede usar cosas como memset
subvertir sin una explícita const_cast
.
Esto es una desventaja entre hacer que el compilador haga cumplir const
y permitir cierta flexibilidad para las interfaces no conscientes de const
.
Lo que conduce a otra limitación, ya que no se ha adoptado universalmente, lo cual se debe en parte a otro problema, que es que usar const
es una proposición de todo o nada. Si comienza a usarlo, deberá propagarlo a través de su base de códigos.
No, esto es posiblemente un Comportamiento no definido (si el objeto original se creó 'const') y en el contexto de esta función se debe suponer que es. Un' const_cast' es legal, pero se escribe en un objeto creado como 'const' , ya sea que hayas descartado la estafa stness o no, es ilegal. –
Bueno, sí, pero si piensas como const en términos de un contrato o prometes que no lo cambiaré (incluso si antes no era const), entonces es posible romperlo. – JohnMcG
Pero puede hacer promesas en forma de comentarios en todos los idiomas y luego subvertirlos. 'const', sin embargo, es una herramienta sin comentarios/integrada que te obliga a no romper el contrato _de manera predeterminada_, mientras que en lenguajes no const correctamente puedes cambiar algo documentado como invariante. –
Otro problema que no se ha mencionado aún es la posibilidad de una interfaz mal diseñada para subvertir const (incluso en ausencia de moldes).
Ejemplo:
class TreeNode {
public:
TreeNode& getParent() const { return *parent_; }
TreeNode& getLeft() const { return *left_; }
TreeNode& getRight() const { return *right_; }
private:
//TreeNode has a pointer to the Tree to enable navigation of the tree.
//Assume that other design constraints mean that this must be a pointer
//rather than a reference.
TreeNode* parent_;
TreeNode* left_;
TreeNode* right_;
};
//This function demonstrates the ability for const to be subverted.
TreeNode& remove_const(TreeNode const& toRemoveConstFrom) {
TreeNode& parent(toRemoveConstFrom.getParent());
TreeNode& leftChild(parent.getLeft());
TreeNode& rightChild(parent.getRight());
return &toRemoveConstFrom == &leftChild ? leftChild : rightChild;
}
La naturaleza intransitivo de const significa que es posible tener una interfaz donde una referencia no const a un objeto puede obtenerse a partir de una referencia const a un objeto. Esto es algo de lo que hay que tener cuidado al diseñar interfaces.
La mayoría de las respuestas a continuación indican cosas como "lo que está mal con const
es que X personas lo hacen Y". Esas no son respuestas sino síntomas. Esas no son cosas malas con const
. Hay apenas cualquier cosa incorrecta con const
... Esas cosas están mal con las personas que no pueden RTFM.
const
es genial. const
es importante. const
-corregir es condición necesaria para que una API sea buena.
Sin embargo, hay dos problemas que he tenido con const
, repetidamente.
No hay manera de marcar una variable como
const
retroactivamente. Debe declarar un código variable, en cuyo caso tiene para inicializarlo inmediatamente. ¿Qué sucede si el código de inicialización contiene unif
? Usted tiene la opción de omitir elconst
(indeseablemente), utilizando el operador?
en lugar deif
(daños a la legibilidad). Java es así, las variables BTW -const
no tienen que inicializarse de inmediato, solo tienen que inicializarse antes de se leen por primera vez, y deben inicializarse en todas las ramas de unif
.No hay forma de especificar que un objeto pasado por referencia a una función no cambiará mientras dure la llamada a la función.
const T& t
hace no significa que el objeto apuntado port
no cambiará, pero solo que la referenciat
no se puede usar para cambiarlo. El compilador aún tiene que suponer que cualquier llamada de función que no vea en podría cambiar el objeto. En algunos casos, eso evita bastantes optimizaciones.
- 1. ¿Qué pasa con gemspec?
- 2. ¿Qué pasa con DCOM?
- 3. ¿Qué pasa con gethostbyname?
- 4. TemplateBinding con convertidor: ¿qué pasa?
- 5. ¿Qué pasa con setScaleX/setScaleY?
- 6. ¿Qué pasa con `std :: set`?
- 7. ¿Qué pasa con las encuestas?
- 8. ¿Qué pasa con DateTime.Parse (myString)?
- 9. T_INLINE_HTML? ¿Qué pasa con esto?
- 10. ¿Qué pasa con [UITableView reloadData]?
- 11. ¿Qué pasa con mi scala.swing?
- 12. ¿Qué pasa con este URI?
- 13. ¿Qué pasa con static_cast con múltiples argumentos?
- 14. ¿No es redundante "const" cuando se pasa por valor?
- 15. ¿Qué pasa con este fragmento de código?
- 16. ¿Qué pasa con el objeto DateTime?
- 17. ¿Qué pasa con mi copia aquí?
- 18. ¿Qué pasa con mi XPath/XML?
- 19. ¿Qué pasa con este ciclo while?
- 20. ¿Qué pasa con LINQ to EF?
- 21. ¿Qué pasa con la clase System.Linq.Expressions.LogicalBinaryExpression?
- 22. ¿Qué pasa con mi código X11?
- 23. ¿Qué pasa con mi cliente Apache CXF?
- 24. ¿Qué pasa con el método jQuery Live?
- 25. ¿Qué pasa con los parámetros de salida?
- 26. ¿Qué pasa con este programa C
- 27. ¿Qué pasa con Linq a SQL?
- 28. ¿Qué pasa con mi matriz de bash?
- 29. ¿Qué pasa con mi archivo app.config?
- 30. ¿Qué pasa con los colores WebSafe?
Creo que son útiles porque hacen que el código sea más fácil de entender. – BlackBear
Necesito hacer una pregunta antes de obtener su respuesta, me parece –
El único problema que veo con 'const' es que su preparación y * inteligibilidad * varía ampliamente según el nivel del programador de C++, (algo de confusión acerca de qué el elemento 'const' se aplica en una declaración compleja, por ejemplo). Además, es parte del lenguaje, y debe utilizarse, siempre que se haya leído el libro de B.Stroustrup :-) –