Copy-on-write и константные методы

197
01 апреля 2018, 20:50

Есть вот такой код:

#include <iostream>
#include <memory>
using namespace std;
template<class T> class copy_on_write_ptr {
    private:
        shared_ptr<T> ptr;
        void detach() {
            T* p = ptr.get();
            if (p && !ptr.unique())
                ptr = make_shared<T>(*p);
        }
    public:
        copy_on_write_ptr(const copy_on_write_ptr<T>&) = default;
        copy_on_write_ptr(T* p) 
            : ptr(p) { }
        const T* operator->() const {
            return ptr.operator->();
        }
        T* operator->() {
            detach();
            return ptr.operator->();
        }
};
struct self {
    const self* ptr() const {
        return this;
    }
    self() = default;
    self(const self&) = default;
};
int main()
{
    copy_on_write_ptr<self> p1(new self());
    cout << p1->ptr() << endl;
    const copy_on_write_ptr<self> p2(p1);
    cout << p2->ptr() << endl;
    cout << p1->ptr() << endl;
}

Выполняю и получаю в консоли

0x4c5a10
0x4c5a10
0x4c5ba0

Почему в последнем случае получается другой адрес? Почему выполнился detach? Я же вызываю константный метод объекта. Ну как так-то?

Что можно сделать чтобы вызов константных методов не приводил к вызову detach? Понятно, что можно объявить p1 константным и detach вызван не будет. Но задача поставлена так, чтобы вызов константных методов класса self не приводил к вызову detach даже если экземпляр класса copy_on_write_ptr сам по себе неконстантный.

Answer 1

По умолчанию для non-const lvalue выбирается оверлоад без const-квалификации.

Что можно сделать чтобы вызов константных методов не приводил к вызову detach?

Ну, собственно, вызвать их как-то, заставив компилятор считать p1 константой:

template<class T> decltype(auto) invokePtr(T const &p) {
    return p->ptr();
}
template<class T> T const &constCast(T const &p) { return p; }
invokePtr(p1);
constCast(p1)->ptr();
const_cast<copy_on_write_ptr<self> const &>(p1)->ptr();
READ ALSO
Парсинг методом рекурсивного спуска

Парсинг методом рекурсивного спуска

Привет! Это мой не первый пост по поводу парсера, но все жеСобственно, проблема такова: есть список(вектор) токенов(указателей на них) и на его...

152
setlocale и linux

setlocale и linux

Пишу на линуксе и никогда не в код не вставляю:

175
Ошибка программы

Ошибка программы

Такие ошибки:

174