Подтвердить что ты не робот

С++ Предотвращение методов const от изменения данных с помощью указателя-члена или ссылки

Скажем, у меня такой простой класс

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

Это справедливо, потому что в методе const его просто указатель сам становится const, а не данными, на которые он указывает. Однако во многих случаях это не то, что я хотел, и мне нужна ошибка компиляции, если метод const пытается изменить содержимое этих элементов (либо напрямую, либо путем вызова неконстантного метода для этого элемента).

Есть ли стандартное решение для этого?

Я думаю, что какой-то класс-оболочка должен быть в состоянии достичь этого, а также должен быть тем, что компилятор оптимизирует, хотя и не сел, чтобы попытаться создать такую ​​вещь, чтобы охватить все случаи, сказав, что strong_const<char*> str и strong_const<int&> (также не уверен в хорошем имени...).

4b9b3361

Ответ 1

Ну, ни std::reference_wrapper, ни std::shared_ptr не обеспечивают const-распространение, поэтому они не более "const-strict", чем обычный указатель.

Я бы рекомендовал создать свой собственный класс распространения сотовой связи (я не уверен - возможно, что-то подобное уже предусмотрено boost - пожалуйста, дайте мне знать в комментариях)

Мое предложение - это класс:

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

Итак, это сработает для вас:

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