Программирование >>  Оптимизация возвращаемого значения 

1 ... 27 28 29 [ 30 ] 31 32 33 ... 96


private: ObjectID old;

mutable string *fieldlValue; mutable int *field2Value; mutable double *fieldSValue; mutable string *field4Value;

Cm. ниже

11 о применении mutable.

LargeObject::LargeObject(Object ID id)

: oid(id), fieldlValue(O), field2Value(0), fieldSValue(0), ... {}

const strings LargeObject::fieldl () const {

if (fieldlValue == 0) {

считать даяные для поля field 1 из базы данных

и задать указатель fieldlValue на них;

return *fieldlValue; }

Каждое поле объекта представлено указателем на необходимые данные, а конструктор LargeObject обнуляет все указатели. Такие нулевые указатели обозначают поля, которые еще не были считаны из базы данных. Каждая функция-член класса LargeObj ect должна проверить состояние указателя поля перед доступом к данным, на которые он указывает. Если указатель нулевой, то соответствующие данные будут считываться из базы перед выполнением любых действий над ними.

При осуществлении отложенной выборки вы сталкиваетесь со следующей проблемой: может потребоваться инициализация нулевых указателей, чтобы они ссылались на реальные данные из любой функции-члена, включая функции с атрибутом const, подобные fieldl. Однако компиляторы ругаются , если вы пытаетесь изменить элементы данных внутри функции-члена с атрибутом const, так что надо найти способ сказать: Все в порядке, я знаю, что делаю . Лучший способ для этого - объявить поля указателя как mutable, чтобы они могли изменяться внутри любой функции-члена, даже внутри функции-члена с атрибутом const. Именно поэтому поля в объекте LargeObj ect были объявлены выше как mutable.

только тогда, когда нужно, чтобы они заняли свое место внутри объекта. Ниже приводится один из способов реализации объектов с подкачкой страниц по требованию:

class LargeObject { public:

LargeObject(ObjectID id) ; const strings fieldl() const; int field2{) const; double fields 0 const; const strings field4{) const;



class LargeObject { public:

const strings fieldl{)

const;

Без изменений.

private:

string *fieldlValue;

He объявляется как mutable, чтобы старые компиляторы принимали его.

const strings LargeObject::fieldl () const {

Объявить указатель fakeThis, указывающий на то же, что и this, но не имеющий атрибута const. LargeObject * const fakeThis = const cast<LargeObject* const>{this);

if (fieldlValue == 0) { fakeThis->fieldlValue = соответствующие данные из базы данных; }

return *fieldlValue; }

Это присваивание допустимо, так как то, на что указывает fakeThis, не имеет атрибута const.

Эта функция использует оператор const cast (см. правило 2), чтобы избавиться от атрибута const в указателе *this. Если ваши компиляторы не поддерживают const cast, вы можете использовать приведение типа языка С:

Приведение типа языка С для эмуляции mutable.

const strings LargeObject:: f ieldl () const

LargeObject * const fakeThis = (LargeObject* const)this;

/ / Как и выше.

Рассмотрим снова указатели внутри объекта LargeObject. Скажем прямо, утомительно было бы обнулять все указатели, а затем проверять каждый из них перед использованием (кроме того, это может привести к ошибкам). К счастью, такую тяжелую работу нетрудно автоматизировать с помощью smart-указателей,

Ключевое слово mutable - относительно недавнее дополнение к языку С++, так что, возможно, ваши компиляторы еше не поддерживают его. В таком сл5Д1ае вам придется найти другой способ убедить компилятор позволить вам изменять данные внутри функции-члена с атрибутом const. С одной стороны, можно использовать стратегию псевдоуказателя this, при которой создается указатель без атрибута cons t, ссылаюшийся на тот же самый объект, что и this. Если вы хотите изменить данные, то обращаетесь к объекту через псевдоуказатель:



о которых рассказано в правиле 28. Используя smart-указатели внутри объекта LargeObject, вы также обнаружите, что больше не нужно объявлять указатели как mutable. Увы, это только временная отсрочка, потому что необходимость в присвоении mutable указателю возникнет снова, как только вы приметесь за реализацию классов smart-указателей.

Отложенная оценка выражения

Заключительный пример отложенного вычисления характерен для числовых приложений. Рассмотрим следующий код:

template<class Т>

class Matrix {...}; Для однородных матриц.

Matrix<int> ml(1000, 1000); То же самое для матриц

Matrix<int> т2(1000, 1000); 1000 на 1000.

Matrix<int> тЗ = ml + m2; Сложить ml и m2.

При обычной реализации operator + используется энергичное вычисление; в этом сл5ае была бы высчитана и возвращена сумма ml и т2. Это достаточно большой объем вычислений (1 ООО ООО операций сложения). Кроме того, для хранения значений потребуется выделение памяти, что также сопряжено с определенными затратами.

Согласно стратегии отложенного вычисления, если способ реализации содержит слишком много работы, она не выполняется. Вместо этого создается структура данных внутри тЗ, которая указывает, что значение тЗ является суммой ml и m2. Такая структура данных состоит всего лишь из указателей на ml и т2 и перечисления, указывающего, что для них должна быть выполнена операция сложения. Конечно же, быстрее задать структуру данных, чем сложить ml и т2, и при этом используется намного меньше памяти.

Предположим, что затем в программе перед использованием тЗ выполняется следующий код:

Matrix<int> т4(1000, 1000);

... Присвоить т4 некоторые значения.

тЗ = т4 * ml;

Теперь можно забыть, что тЗ было равно сумме ml и m2 (и таким образом сэкономить затраты на вычисления), и считать с этого момента, что тЗ равно произведению т4 на ml. Но само умножение выполняться не будет. Зачем беспокоиться? Хорошие программисты ленивы, помните?

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



1 ... 27 28 29 [ 30 ] 31 32 33 ... 96

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика