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

1 ... 66 67 68 [ 69 ] 70 71 72 ... 96


Подсчет ссылок пригодится, даже если эффективность не имеет для вас решающего значения. Если вас обременяет неопределенность того, кто может удалить объект, подсчет ссылок - именно тот метод, который облегчит вашу ношу. Многие программисты преданы методу подсчета ссылок только по этой причине.

В заключение разговора о подсчете ссылок надо указать, как устранить последний недочет. Уменьшая счетчик ссылок на объект на единицу, функция RCObject: : removeRef erence проверяет, становится ли он равным 0. Если это так, то функция removeRef erence уничтожает объект, выполняя оператор delete this. Данная операция безопасна, только если объект был создан при помощи вызова оператора new, поэтому нужен какой-то способ, гарантирующий, что объекты RCObj ect создаются только так.

Здесь это делается по соглашению, класс RCObj ect предназначен для использования в качестве базового класса для объектов со счетчиками ссылок на значения, и на такие объекты нужно ссылаться только при помощи интеллектуальных указателей RCPtr. Кроме того, экземпляры объектов должны создаваться только при помощи прикладных объектов, которые представляют используемые совместно значения; классы, описывающие объекты значений, не должны быть доступны для общего использования. В рассматриваемом примере классом для объектов значений является класс StringValue, и чтобы ограничить его использование, он сделан закрытым элементом класса string. Только объекты String могут создавать объекты StringValue, поэтому автор класса String должен гарантировать, что такие объекты будут создаваться при помощи оператора new.

Создание объектов RCObj ect будет возможно только в Kje. Вся ответственность за выполнение этого ограничения ложится на хорошо определенный набор классов. Кроме того, гарантируется, что только этот набор классов способен создавать объекты RCObject. Пользователи не могут слзайно (или намеренно) сформировать объекты RCObject другим образом. Право создавать объекты со счетчиком ссылок ограничено, и оно сопровождается сопутствующей ответственностью за соблюдение правил, контролирующих создание объектов.

Правило 30. Применяйте proxy-классы

Мир многомерен, но язык С++ еще не осознал этого. По крайней мере, к такому выводу подводит предложенная в языке реализация поддержки массивов. Можно создавать двумерные, трехмерные, даже п-мерные массивы в языках Fortran, Basic, даже в Cobol (Fortran позволяет работать только с семью измерениями, но не будем придираться), а можно ли сделать это в языке С++? Только иногда и только частично.

Например, разрешается написать:

int data[10] [20] ; Двумерный массив 10 на 20.

Но соответствующая конструкция, использующая переменные для задания размерности массива, недопустима:

void processlnput {int diml, int dim2) {



int data[diml][dim2]; Ошибка! Размер массива

... должен быть известен

} во время компиляции.

Это недопустимо даже при динамическом выделении памяти:

int *data =

new int[diml][dim2]; Ошибка!

Реализация двумерных массивов

Многомерные массивы так же полезны в С++, как и в любом другом языке, поэтому важно найти хороший способ обеспечить их поддержку. Обычный метод стандартен для С++: создать класс для представления нужных вам, но отсутствующих в языке объектов. Следовательно, можно определить шаблон класса для двумерных массивов:

template<class Т> class Array2D { public:

ArraY2D{int diml, int dim2);

Теперь достаточно определить нужные массивы:

Аггау20<1пЬ> data{10, 20); Нормально.

Аггау20<£loat> *data =

new Array2D<float>{10, 20); Нормально,

void processlnput(int diml, int dim2) {

Array2D<int> data(diml, dim2); Нормально.

Использовать эти объекты массивов не совсем просто. Если следовать традиционному синтаксису С и С++, то для индексирования массивов должны использоваться квадратные скобки:

cout data[3] [6] ;

Но как объявить в классе оператор Array 2D индексирования, который позволит сделать это?

Первое побуждение - объявить функции operator [ ] [ ], например, так:

template<class Т> class Array2D { public:

Объявления, которые не будут компилироваться.

Т& operator [] [] (int indexl, int index2) ;

const TSc operator [] [] (int indexl, int index2) const;



Но функция operator [ ] [ ] не существует, и не думайте, что ваши компиляторы об этом забудут. (См. в правиле 7 полный список операторов, как перегружаемых, так и неперегружаемых.) Придется сделать что-то другое.

Если для вас приемлем такой синтаксис, то вы можете последовать примеру множества языков программирования, использующих для индексации массива круглые скобки. Для этого вам достаточно перегрузить функцию operator ():

template<class Т> class Аггау20 { public:

Объявления, которые будут компилироваться.

Т& operator()(int indexl, int index2);

const T& operator{)(int indexl, int index2) const;

Тогда пользователи будут использовать массивы следующим образом:

cout data(3 , 6);

Такие массивы легко реализовать и обобщать на произвольное число измерений. Недостаток этого подхода состоит в том, что объекты Array 2D больше не похожи на встроенные массивы. Фактически, доступ к элементу (3, 6) массива data выглядит как вызов функции.

Если отказаться от мысли о том, что массивы должны быть похожи на эмигрантов из языка Fortran, можно снова обратиться к записи оператора индексирования с помощью квадратных скобок. Хотя operator [ ] [ ] и не существует, допустимо написать код, который имитирует его использование:

int data[10] [20] ;

cout data[3] [6] ; Нормально. Что это дает?

Переменная data в действительности не будет двумерным массивом, а одномерным из 10 элементов. Каждый из этих 10 элементов, в свою очередь, представляет собой массив из 20 элементов, поэтому выражение data [ 3 ] [ 6 ] на самом деле означает (data [ 3 ] ) [ 6 ], то есть седьмой элемент массива, который является четвертым элементом массива data. Короче говоря, значение, ползаемое в результате первого применения квадратных скобок, является другим массивом, поэтому второе применение скобок извлекает элемент из второстепенного массива.

Можно выполнить то же самое для класса Array 2D, перегрузив функцию operator [ ] так, чтобы она возвращала новый класс ArraylD. Затем снова перегрузить функцию operator [ ] в классе ArraylD, в результате чего она будет возвращать элемент в исходном двумерном массиве:

template<class Т> class Array2D { public:

class ArraylD {



1 ... 66 67 68 [ 69 ] 70 71 72 ... 96

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