A menudo es bastante confuso para los recién llegados en C++ que las funciones de miembros const puedan llamar a métodos no const en objetos referenciados por la clase (ya sea por puntero o referencia). Por ejemplo, la siguiente es perfectamente correcta:Propagar constness a los datos apuntados por las variables miembro
class SomeClass
{
class SomeClassImpl;
SomeClassImpl * impl_; // PImpl idiom
public:
void const_method() const;
};
struct SomeClass::SomeClassImpl
{
void non_const_method() { /*modify data*/ }
};
void SomeClass::const_method() const
{
impl_->non_const_method(); //ok because impl_ is const, not *impl_
};
Sin embargo, sería a veces ser bastante útil si el constness se propagaría a los objetos puntiagudos (utilicé voluntariamente el idioma PImpl porque es uno de los casos en el que creo " propagación de la consistencia "sería muy útil).
Cuando el uso de punteros, esto fácilmente se puede lograr mediante el uso de algún tipo de puntero inteligente con operadores sobrecargados en constness:
template < typename T >
class const_propagating_ptr
{
public:
const_propagating_ptr(T * ptr) : ptr_(ptr) {}
T & operator*() { return *ptr_; }
T const & operator*() const { return *ptr_; }
T * operator->() { return ptr_; }
T const * operator->() const { return ptr_; }
// assignment operator (?), get() method (?), reset() method (?)
// ...
private:
T * ptr_;
};
Ahora, sólo hay que modificar SomeClass::impl_
ser un const_propagating_ptr<SomeClassImpl>
para obtener lo que se desea .
Así que tengo algunas preguntas acerca de este:
- ¿Hay algunos problemas con la propagación constness que he pasado por alto?
- Si no, ¿hay alguna biblioteca que proporcione clases para obtener la propagación de la consistencia?
- ¿No sería útil que los punteros inteligentes comunes (unique_ptr, shared_ptr, etc.) proporcionen algún medio para obtener este comportamiento (por ejemplo, a través de un parámetro de plantilla)?
¿Qué sucede si solo copio el puntero inteligente? Voila, tengo uno no const. –
'T const * const operator ->() const {return ptr_; } '- probablemente no sea necesario el segundo' const' aquí –
@Alf y @robin: el boceto que di de una posible implementación probablemente esté plagado de errores (a pesar de su tamaño pequeño :)), no es el punto central del pregunta. Sin embargo, ¡tus comentarios son realmente apreciados! En cuanto al problema de la copia, no veo en este momento cómo podemos evitar que eso sea posible, pero a menudo no puedes evitar disparos en el pie (por ejemplo, siempre puedes "const_cast" constness de distancia, no significa que const sea inútil). En cuanto al segundo comentario, tienes razón @robin, lo hice equivocadamente para evitar que 'ptr_' sea ... –