2010-09-11 17 views
5

En C++, ¿es un método const devolver un puntero a un objeto no const considerado mala práctica? Por ejemplo. considerar los siguientes métodos:En C++, ¿es un método const devolver un puntero a un objeto no const considerado mala práctica?

// Makes perfect sense 
bool isActive() const { return m_isActive; } 

// Makes perfect sense, both consts ensure nothing is modified 
const SomeObject* someObject() const { return m_someObject; } 

// Makes perfect sense, no const because SomeObject is mutable, 
// thus MyClass is indirectly mutable 
SomeObject* someObject() { return m_someObject; } 

// Makes no sense, if you're just returning a pointer to a const object, 
// then the method should clearly be const since nothing can be modified 
const SomeObject* someObject() { return m_someObject; } 

La última combinación me intriga: ¿La siguiente considera una mala práctica?

SomeObject* someObject() const { return m_someObject; } 

Debido a que la clase que método devuelve no es constante, pero el método es, es algo inútil, ya que podría modificar SomeObject y por lo tanto indirectamente modificar su clase ... así que se forma considera una mala práctica? p.ej. ¿Deberías usar solo uno de los siguientes en lugar de él?

const SomeObject* someObject() const { return m_someObject; } 
SomeObject* someObject() { return m_someObject; } 

situación del mundo real: Estoy escribiendo un juego de teléfono inteligente que tiene una clase Game. La clase Game contiene varios métodos que devuelven punteros a clases de utilidad como InputManager, AudioManager, etc.

class Game 
{ 
public: 
    InputManager* inputManager() const { return m_inputManager; } 
    ... 

private: 
    InputManager* m_inputManager; 
    ... 
} 

¿tiene algún sentido en absoluto para hacer inputManager() const, ya que el objeto se vuelve no es? (Y no debe ser, ya que las necesidades InputManager ser mutable por su estado para ser actualizado, etc.)

O debería eliminar el modificador del método const para reflejar con más precisión el comportamiento del método? De esa manera, si tuviera un const Game, no podría llamar al inputManager() y luego meterme con el administrador de entrada Game aunque el Game fuera const.

Respuesta

3

Depende de si el puntero no const apunta hacia algo dentro del objeto const, o si es memoria recientemente asignada que debe ser variable.

Considere algo que devolvió una copia de una cadena; está bien que la copia devuelta sea no const, incluso si la cadena original es const. La propiedad de la copia se transfiere desde el método al código de llamada; asegurar que la copia sea destruida apropiadamente es ahora el problema del código de llamada (muy posiblemente un problema muy leve).

Sin embargo, sería una muy mala idea devolver un puntero no const a algo desde dentro de un objeto const.

+1

Si el objeto A "posee" el objeto B, y desea tratar a A como const, entonces un acceso a B también debería ser const. Si A no posee B, entonces todas las apuestas están desactivadas. Como señala OP, es un problema de estilo en C++. Un lenguaje más pedante haría cumplir esto. –

2

Eso es perfectamente aceptable. Un método const significa que no está modificando el objeto cuyo método está llamando; no dice nada sobre ningún otro objeto. Por supuesto, ese objeto podría ser parte de "esto", o podría ser "esto", pero eso está más allá del punto.

"const" en general es más que una promesa, pero la idea subyacente es la misma: un método const dice que "esto" es const, y eso es todo.

+1

Bueno, ni siquiera tanto que 'esto' sea constante, tanto como no modificaré 'esto' usando este método en particular. Creo que eso es lo que estás diciendo en este primer párrafo, pero parecía un poco incierto. Const generalmente es una promesa de no cambiar algo a través de los medios particulares que se marcan const. Para puntero-a-const, referencia-a-const, etc., el objeto al que se hace referencia es a menudo no const a través de alguna otra referencia y modificado a través de eso. Las referencias de Const en los datos de los miembros a menudo son un ejemplo de ello, una promesa de que la clase no modificará el objeto al que hace referencia, pero nada más. – Steve314

0

En mi opinión, devolver un puntero de miembro es una mala idea, ya sea const o no.

Cuando un objeto devuelve un identificador de su miembro privado, otros pueden cambiar el miembro privado a través de este identificador. El estado del objeto puede ser inconsistente y causar muchos problemas. Incluso si hay una const, la persona que llama aún puede usar const cast para eludir esta comprobación. Por lo tanto, no es una buena idea devolver el control de ningún miembro privado del objeto.

+1

Si un usuario de su clase usa 'const_cast' para eludir las protecciones que usted presentó, entonces se merecen los problemas que tengan. –

+0

@Dennis Estoy completamente de acuerdo. Como nota al margen, otra respuesta que doy a personas que piensan que idiomas como C# y Java no tienen 'const 'es A Good Thing ™ cuando dicen que' const' es inútil porque la gente puede usar 'const_cast' como" reflejo ". Una palabra. :) –

0

No creo que const importa mucho aquí.

Normalmente se ha lanzado al devolver un mango (puntero, referencia) a un atributo:

  • se vincula a los usuarios una aplicación particuler, por lo que es imposible cambiarlo
  • que hace que sea imposible de hacer cumplir invariantes (versiones no const), puede que no tenga tales ahora, pero que nunca ahora lo que el futuro le dará

Si usted comience a hacer atributos directamente accesibles, que son tan buenos como public.

Ejemplos:

class Foo 
{ 
public: 
    std::vector<Bar> const& bars() const; // Ooops, impossible to move to a `deque` 
             // or to enable polymorphic behavior 
private: 
    std::vector<Bar> mBars; 
}; 

Es mejor que regresar por valor, de esta manera si cambia sus partes internas siempre se puede proporcionar un nuevo método y hacer algo de conversión en el viejo no romper la interfaz (marcándolo como obsoleto y todo).

Recuerde: ¡personas han sido enviadas a la cárcel por exponer sus partes privadas!

0

En su caso, los objetos Game y InputManager parecen ser solos. Si este es el caso, solo necesita asegurarse de que solo exista una instancia de Juego (que contenga solo un Administrador de entrada), y omita los decoradores de const. Como se sugirió anteriormente, en este caso, devolvería una referencia a los objetos contenidos, sin punteros.

Cuestiones relacionadas