2015-02-26 9 views
12

che ho una classe semplice come questoC++ Impedire metodi const di modificare i dati tramite un puntatore membro o riferimento

class Foo 
{ 
public: 
    void foo()const 
    { 
     str[5] = 'x'; 
     obj->changeTheWorld(); 
     x = 4; 
     y.get() = 5; 
     obj2->changeTheWorld(); 
    } 
private: 
    char *str; //some referenced data, not owned by Foo 
    ComplexObj *obj; //some referenced data, not owned by Foo 
    int &x; //references as well 
    //wrapped reference, but has a "T& get()const" 
    std::reference_wrapper<int> y; 
    //an occasionally useful pointer wrapper for complex memory cases 
    //but has a "T* get()const" 
    std::shared_ptr<ComplexObj> obj2; 
}; 

Ciò è valido in quanto nel metodo const, è proprio il puntatore stesso che diventa const, non i dati a cui punta. Tuttavia, in molti casi non è quello che desideravo e voglio un errore di compilazione se un metodo const tenta di modificare questi contenuti dei membri (direttamente o chiamando un metodo non-const su quel membro).

Esiste una soluzione standard a questo?

Penso che una sorta di classe wrapper dovrebbe essere in grado di raggiungere questo obiettivo, e dovrebbe anche essere qualcosa che il compilatore ottimizza, anche se non si è seduto per provare a progettare una cosa del genere per coprire tutti i casi dando un strong_const<char*> str e strong_const<int&> (anche se non sono sicuro di un buon nome ...).

+18

C'è una proposta di C++ 17, [propagate_const] (http://www.open-std.org/jtc1/sc22/wg21/docs /papers/2015/n4372.html). –

+1

[vedi qui] (http://stackoverflow.com/questions/28618592/is-questo-a-legitimo-del-intervento-interpretazione-e-if-not-come-do-i-do-questo/) o [qui] (http://stackoverflow.com/questions/4729820/propagate-constness-to-data-pointed-by-member-variables) per alcune opzioni –

+0

'std :: string' si comporterebbe nel modo desiderato . Non sono sicuro del motivo per cui il riferimento sarebbe compilato, mi sembra sbagliato. –

risposta

4

Bene, né std::reference_wrapperstd::shared_ptr non forniscono la propagazione const, quindi non sono più "costanti" del puntatore normale.

mi consiglia di fare la propria classe const propagazione (non sono sicuro - forse qualcosa di simile è già prevista dalla spinta - per favore fatemelo sapere nei commenti)

La mia proposta è questa classe:

#include <memory> // for pointer_traits 

template <typename Pointer> 
class ConstPropagatePointer 
{ 
public: 
    using element_type = typename std::pointer_traits<Pointer>::element_type; 
    using pointer = typename std::pointer_traits<Pointer>::pointer; 
    using const_pointer = element_type const * const; 
    using reference = element_type&; 
    using const_reference = element_type const&; 

    ConstPropagatePointer(Pointer ptr) : ptr(ptr) {} 
    pointer operator ->() 
    { 
     return &(*ptr); 
    } 
    const_pointer operator ->() const 
    { 
     return &(*ptr); 
    } 
    reference operator *() 
    { 
     return *ptr; 
    } 
    const_reference operator *() const 
    { 
     return *ptr; 
    } 
private: 
    Pointer ptr; 
}; 

in modo che funziona per voi:

class Foo 
{ 
public: 
private: 
    ConstPropagatedPointer<char*> str; 
    ConstPropagatedPointer<ComplexObj*> obj; 
    ConstPropagatedPointer<std::shared_ptr<ComplexObj>> obj2; 
}; 
Problemi correlati