2015-02-26 6 views
12

że mam proste klasy takC++ Zapobieganie const metody z zmianę danych poprzez wskaźnik zarejestrował lub odniesienie

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; 
}; 

Jest to ważne, ponieważ w metodzie const, to tylko sam wskaźnik, który staje się const, nie dane, na które wskazuje. Jednak w wielu przypadkach nie jest to, co chciałem i chcę błąd kompilacji, jeśli metoda const próbuje zmienić zawartość tych elementów (bezpośrednio lub przez wywołanie metody non-const na tym elemencie).

Czy istnieje standardowe rozwiązanie tego problemu?

Myślę, że jakaś klasa otoki powinna być w stanie to osiągnąć, a także powinna być czymś, co kompilator optymalizuje, chociaż nie usiadł, aby spróbować zaprojektować coś takiego, aby pokryć wszystkie przypadki, mówiąc: strong_const<char*> str i strong_const<int&> (również nie jestem pewien co do dobrego imienia ...).

+18

jest to propozycja dla C++ 17, [propagate_const] (http://www.open-std.org/jtc1/sc22/wg21/docs /papers/2015/n4372.html). –

+1

[patrz tutaj] (http://stackoverflow.com/questions/28618592/is-this-a-legitimate-use-of-reinterpret-cast-and-if-not-how-do-i-do-this/) lub [tutaj] (http://stackoverflow.com/questions/4729820/propagate-constness-to-data-pointed-by-member-variables) dla niektórych opcji –

+0

'std :: string' zachowałoby się tak, jak chcesz . Nie wiem, dlaczego odnośnik się skompilował, co wydaje mi się błędne. –

Odpowiedz

4

Cóż, ani std::reference_wrapper ani std::shared_ptr nie zapewniają propagacji stałej, więc nie są bardziej "const-strict" niż zwykły wskaźnik.

polecam zrobić własną klasę propagacji const (nie jestem pewien - może coś podobnego jest już przewidziane przez Boost - proszę dać mi znać w komentarzach)

Moja propozycja jest ta klasa:

#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; 
}; 

tak, że będzie pracować dla Ciebie:

class Foo 
{ 
public: 
private: 
    ConstPropagatedPointer<char*> str; 
    ConstPropagatedPointer<ComplexObj*> obj; 
    ConstPropagatedPointer<std::shared_ptr<ComplexObj>> obj2; 
}; 
Powiązane problemy