Создание ленивого вектора: проблема с константой - PullRequest
0 голосов
/ 15 февраля 2009

Я написал небольшой класс "ленивый вектор" (или вектор с задержкой), который должен выглядеть как std::vector и использоваться везде, где используется std::vector, но он загружает свои элементы "лениво", то есть он будет загружать элемент n (и, возможно, еще несколько) с диска всякий раз, когда кто-то обращается к элементу n. (Причина в том, что в моем приложении не все элементы помещаются в память.)

Вот этот класс LazyVector, но есть проблема с const функциями-членами, которые используют такой вектор, см. Ниже.

template<class T>
class LazyVector {
  std::vector<T> elems_;
  void fetchElem(unsigned n){
    // load the n-th elem from disk into elems_ etc
  }
public:
  const T& operator[](unsigned n) const {
    fetchElem(n); // ERROR: ... discards qualifiers       
    return elems_[n];
  }
  T& operator[](unsigned n) {
    fetchElem(n);
    return elems_[n];
  }
  // and provide some other std::vector functions
};

Как я уже сказал, существует проблема, когда функция-член const запрашивает элемент LazyVector. По природе LazyVector доступ к элементу не const, то есть он изменит вектор vec ниже, что запрещено в этом контексте. Функция-член foo должна быть const и не может быть изменена. Как я могу решить это?

class Foo {
  LazyVector<const std::string*> vec;
  void fct(int n) const { // fct must be const 
    const std::string* str = vec[n];
    // do something with str 
  }
};

Ответы [ 6 ]

7 голосов
/ 15 февраля 2009

Вы можете использовать изменяемые данные члена или const_cast в реализации вашего класса LazyVector. Таким образом, вы можете создать иллюзию константности, необходимую вашему потребляющему классу, фактически не будучи константой.

4 голосов
/ 15 февраля 2009

Используйте ключевое слово mutable в элементе данных elems_.

3 голосов
/ 15 февраля 2009

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

class LazyVector
{
    public:
        int const& operator[](int index) const
        { 
            data->fetchElement(index);
            return data->get(index);
        }
    private:
        std::auto_ptr<LazyDataCache>   data;
};

Здесь данные - это указатель (умный указатель, но все же указатель). Пока указатель не меняется, вы не меняете стоимость LazyVector. Но вы все равно можете вызывать неконстантные методы для объекта, на который указывают данные (помните, что указатель является const, а НЕ объектом, на который указывает).

2 голосов
/ 15 февраля 2009

Для таких вещей ключевое слово mutable предназначено для. Поместите ваш кеш как изменяемый объект в ваш класс. Это потому, что ваш кеш, похоже, не меняет логическое содержимое / состояние вашего объекта (т.е. элементы вашего вектора или его размер не меняются).

const методы не утверждают, что они физически не изменяют ваш объект. Они утверждают, что не будут изменять абстрактную ценность вашего объекта. Детали реализации, которые абстрагированы, могут все еще быть изменены константными функциями.

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

Прочтите Какова семантика функции-члена const Ответ Энтони Уильямса.

1 голос
/ 15 февраля 2009

Грубый способ сделать это будет

LazyVector* p = const_cast<LazyVector*>(this);
p->fetch();

Я думаю, будет лучший способ сделать это. Но это будет работать.

1 голос
/ 15 февраля 2009

Объявить elems_ как mutable:

mutable std::vector<T> elems_;

Есть и другие вещи, которые вы можете сделать, но это поддерживаемый способ сделать это.

Редактировать: еще один способ сделать это - добавить другого члена и установить его в конструкторе:

std::vector<T> *mutable_elems_;

mutable_elems_(&elems_)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...