Вопрос по снятию константности c const_iterator
От: Аноним  
Дата: 23.01.08 11:40
Оценка:
Мейерс рекомендует реализовывать неконстантную функцию посредством константной версии путем снятия константности со второй.
Вопрос: есть ли какие-либо гарантии стабильности (правильности?) работы следующего примера:

template <typename Var, TID>
class Container
{
private:
    typedef std::map<TID, Var> Container_Type;
    Container_Type vars;
public:
    Var& Get(TID ID)
    {
        // можно ли?
        return const_cast<Var&>(static_cast<const Container&>(*this).Get(ID));    // call constant version of Get
    }
    const Var& Get(TID ID) const
    {
        Container_Type::const_iterator it = vars.find(ID);
        assert(it != vars.end());
        return it->second;
    }
    const Data_Type& operator[](TID ID) const                      { return Get(ID).Value; }
    Data_Type& operator[](TID ID)                                  { return Get(ID).Value; }
};

struct Var
{
    int Value;
};

Container<int, Var> c;
Re: Вопрос по снятию константности c const_iterator
От: Bell Россия  
Дата: 23.01.08 12:45
Оценка:
Здравствуйте, Аноним, Вы писали:

Вообще это достаточно распространенный прием. На основании чего возникли сомнения?
Любите книгу — источник знаний (с) М.Горький
Re: Вопрос по снятию константности c const_iterator
От: Erop Россия  
Дата: 23.01.08 12:55
Оценка: 2 (2)
Здравствуйте, Аноним, Вы писали:

А>Вопрос: есть ли какие-либо гарантии стабильности (правильности?) работы следующего примера:

<...>

AFAIK есть, так как second -- это lvalue.
Правда какие-нибудь проксистроители могут что-то такое нарожать, но на первый взгляд дырок не видно.

Но IMHO
Автор: Erop
Дата: 04.09.07
так и лучше и понятнее и надёжнее защита от изысков реализаций STL:
template <typename Var, TID>
class Container
{
private:
    typedef std::map<TID, Var> Container_Type;
    mutable Container_Type vars;
    Var& doGet( TID ID ) const
    {
        Container_Type::iterator it = vars.find(ID);
        assert(it != vars.end());
        return it->second;
    }
public:
    Var& Get(TID ID)
    {
        return doGet( ID );
    }
    const Var& Get(TID ID) const
    {
        return doGet( ID );
    }
};
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[2]: Вопрос по снятию константности c const_iterator
От: Аноним  
Дата: 23.01.08 13:09
Оценка:
Здравствуйте, Bell, Вы писали:

B>Здравствуйте, Аноним, Вы писали:


B>Вообще это достаточно распространенный прием. На основании чего возникли сомнения?


здесь
Автор: Erop
Дата: 23.01.08
уже опередили меня.
т.е. опасения связаны с тем, что, как мне кажется, в стандарте не описано, что const версии должны реализовываться аналогично не const, т.е. при снятии константности запись будет вестить не в область где хранятся реальные данные, а какой-нибудь буфер (кеш) который возвращают const версии. типа того
Re[2]: Вопрос по снятию константности c const_iterator
От: Аноним  
Дата: 23.01.08 13:26
Оценка:
Здравствуйте, Erop, Вы писали:

E>Здравствуйте, Аноним, Вы писали:


E>AFAIK есть, так как second -- это lvalue.

так то оно так, но где гарантия, что в одной из реализаций библиотеки const_iterator будет возращать итератор в буфере (кеше) в который вообще бессмысленно вести запись, т.к представляет собой динамически изменяемый слепок реальных данных.

E>Но IMHO
Автор: Erop
Дата: 04.09.07
так и лучше и понятнее и надёжнее защита от изысков реализаций STL:[c]template <typename Var, TID>

интересно, спасибо
Re[3]: Вопрос по снятию константности c const_iterator
От: Erop Россия  
Дата: 23.01.08 13:46
Оценка:
Здравствуйте, Аноним, Вы писали:

E>>AFAIK есть, так как second -- это lvalue.

А>так то оно так, но где гарантия, что в одной из реализаций библиотеки const_iterator будет возращать итератор в буфере (кеше) в который вообще бессмысленно вести запись, т.к представляет собой динамически изменяемый слепок реальных данных.

Дык я про то же
Другое дело, что есть подозрение, что это не нужно не для чего, но гарантий нет, конечно...

E>>Но IMHO
Автор: Erop
Дата: 04.09.07
так и лучше и понятнее и надёжнее защита от изысков реализаций STL:[c]template <typename Var, TID>

А>интересно, спасибо
Всегда пожалуйста. Обращайся
p. s.

Для спасибо есть кнопочка
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[2]: Вопрос по снятию константности c const_iterator
От: Кодт Россия  
Дата: 23.01.08 14:31
Оценка: 2 (2)
Здравствуйте, Erop, Вы писали:

E>Правда какие-нибудь проксистроители могут что-то такое нарожать, но на первый взгляд дырок не видно.


Поскольку const_iterator — это суперкласс iterator (в смысле LSP), даже если там прокси используются, то в общем случае лучше кастить от неконстантного к константному.
class Foo
{
public:
    Value const& get(Key k) const { return const_cast<Foo&>(*this).get(k); }
    Value& get(Key k); // здесь программист должен дать гарантии, что сам объект не меняется
};

Естественно, что эти гарантии — достаточно произвольны. Например, если считается, что образы отсутствующих ключей — это дефолтные значения, то можно спокойно сделать mutable map и пользоваться оператором [], который при промахе добавляет элемент.

Или же, раз мы всё равно в шаблоне — то написать шаблон функции.
template<bool C, class T> struct opt_const : if_c< C, const T, T > {};

class Foo
{
    typedef map<Key, Value> the_map;
    the_map map_;
    .....

public:
    Value const& get(Key k) const { return do_get<true>(*this,k); }
    Value& get(Key k) { return do_get<false>(*this,k); }
private:
    template<bool Const>
    static
    typename opt_const<Const,Value>::type &
    do_get(typename opt_const<Const,Foo>::type &here, Key k)
    {
        typedef typename if_c<Const, typename the_map::const_iterator, typename the_map::iterator>::type the_iterator;
        the_iterator i = here.map_.find(k);
        assert(i != here.map_.end());
        return i->second;
    }
};


Вот как-то так.
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.