С++ - язык, который изучается постепенно.ГЛАВА 13. Управление памятью с применением ведущих указателей

Недорогой но высококачественный сайт. Такое может быть? Да. У нас может быть всё. Достойное качество по доступной цене.
С точки зрения нашей студии создание сайта недорого значит, прежде всего, отменно, технологично и потом уже - недорого.
Удаленная форма работы с клиентами оптимизирует наши расходы и мы можем делать сайты по всему миру. Вам совсем не нужно приезжать к нам. Мы сэкономим Ваше время и средства.

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


По последним данным, на рынке продается по крайней мере 2 768 942 книги о С++, не говоря уже о всевозможных курсах, обучающих программах, журналах и семинарах с коктейлями. И все же в этом изобилии наблюдается удручающее однообразие. Просматривать полку книг о С++ в книжном магазине ничуть не интереснее, чем литературу по бухгалтерии. В сущности, все книги пересказывают одно и то же и отличаются разве что по весу и количеству цветов в диаграммах и таблицах.На сегодняшний день язык Си и языки основанные на синтаксисе Си (например, C++, Java, C#) наиболее популярны в практическом программировании. Язык Си имеет массу достоинств, он прост в изучении и лаконичен. Элементы языка Си (массивы, функции, указатели) максимально приближены к архитектуре компьютеров. Студия Web-дизайна, создание, раскрутка сайта

                    



Материалы книги получены с http://www.itlibitum.ru/

Управление памятью с применением ведущих указателей

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

Специализированные ведущие указатели

Простейшая стратегия заключается в создании специализированного класса ведущего указателя или шаблона, который знает о локальном пуле и использует глобальную перегрузку оператора new.

struct Pool { ... }; // Как и раньше

void* operator new(Pool* p); // Выделение из пула

template <class Type>

class PoolMP {

private:

Type* pointee;

PoolMP(const PoolMP<Type>&) {} // Копирование не разрешено...

PoolMP<Type>& operator=(const PoolMP<Type>&)

{ return *this; } // ...и присваивание тоже

public:

PoolMP(Pool* p) : pointee(new(p) Type) {}

~PoolMP() { pointee->~Type(); }

Type* operator->() const { return pointee; }

};

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

На это можно возразить, что копирование и присваивание все же следует поддерживать, но с

использование операторов new и delete по умолчанию. В этом случае конструктор копий и оператор = работают так же, как и для обычного ведущего указателя.

Обратные указатели на пул

Чтобы поддерживать копирование и присваивание в пуле, можно запоминать адрес пула.

template <class Type>

class PoolMP {

private:

Type* pointee;

Pool* pool;

public:

PoolMP(Pool* p) : pointee(new(p) Type), pool(p) {}

~PoolMP() { pointee->Type::~Type(); }

PoolMP(const PoolMP<Type>& pmp) : pointee(new(pool) Type(*pointee)) {}

PoolMP<Type>& operator=(const PoolMP<Type>& pmp)

{

if (this == &pmp) return *this;

delete pointee;

pointee = new(pool) Type(*pointee);

return *this;

}

Type* operator->() const { return pointee; }

};

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

Сосуществование с обычными ведущими указателями

Предложенное решение отнюдь не идеально. Интерфейс PoolMP открывает многое из того, о чем следовало бы знать только классам. Более того, если вам захочется совместно работать с объектами из пула и объектами, размещенными другим способом (например, с помощью стандартного механизма), начинаются настоящие трудности. Ценой добавления v-таблицы мы сможем значительно лучше инкапсулировать отличия в стратегиях управления памятью.

template <class Type>

class MP {

protected:

MP(const MP<Type>&) {} // Копирование не разрешено

MP<Type>& operator=(const MP<Type>&)

{ return *this; } // Присваивание - тоже

MP() {} // Используется только производными классами

public:

virtual ~MP() {} // Освобождение выполняется производными классами

virtual Type* operator->() const = 0;

};

template <class Type>

class DefaultMP : public MP<Type> {

private:

Type* pointee;

public:

DefaultMP() : pointee(new Type) {}

DefaultMP(const DefaultMP<Type>& dmp)

: pointee(new Type(*dmp.pointee)) {}

virtual ~DefaultMP() { delete pointee; }

DefaultMP<Type>& operator=(const DefaultMP<Type>& dmp)

{

if (this == &dmp) return *this;

delete pointee;

pointee = new Type(*dmp.pointee);

return *this;

}

virtual Type* operator->() const { return pointee; }

};

template <class Type>

class LocalPoolMP : public MP<Type> {

private:

Type* pointee;

Pool* pool;

public:

LocalPoolMP(Pool* p)

: pointee(new(p) Type), pool(p) []

LocalPoolMP(const LocalPoolMP<Type>& lpmp)

: pointee(new(lpmp.pool) Type(*lpmp.pointee)), pool(lpmp.pool) {}

virtual ~LocalPoolMP() { pointee->Type::~Type(); }

LocalPoolMP<Type>& operator=(const LocalPoolMP<Type>& lpmp)

{

if (this == &lpmp) return *this;

pointee->Type::~Type();

pointee = new(pool) Type(*lpmp.pointee);

return *this;

}

virtual Type* operator->() const { return pointee; }

};

Теперь DefaultMP и LocalPoolMP можно использовать совместно - достаточно сообщить клиенту, что они принадлежат к типу MP<Type>&. Копирование и присваивание поддерживается для тех классов, которые взаимодействуют с производными классами, но запрещено для тех, которые знают только о базовом классе. В приведенном коде есть одна тонкость: операторная функция LocalPoolMP::operator= всегда использует new(pool) вместо new(lpmp.pool). Это повышает безопасность в тех ситуациях, когда два ведущих указателя поступают из разных областей действия и разных пулов.

Невидимые указатели

Раз уж мы «заплатили вступительный взнос» и создали иерархию классов ведущих указателей, почему бы не пойти дальше и не сделать эти указатели невидимыми? Вместо применения шаблона нам придется реализовать отдельный класс указателя для каждого класса указываемого объекта, но это не слишком большая цена за получаемую гибкость.

// В файле foo.h

class Foo {

public:

static Foo* make(); // Использует выделение по умолчанию

static Foo* make(Pool*); // Использует пул

virtual ~Foo() {}

// Далее следуют чисто виртуальные функции

};

// В файле foo.cpp

class PoolFoo : public Foo {

private:

Foo* foo;

Pool* pool;

public:

PoolFoo(Foo* f, Pool* p) : foo(f), pool(p) {}

virtual ~PoolFoo() { foo->~Foo(); }

// Переопределения функций класса, делегирующие к foo

};

class PFoo : public Foo {

// Обычный невидимый указатель

};

class ConcreteFoo : public Foo { ... };

Foo* Foo::make()

{

return new PFoo(new ConcreteFoo);

}

Foo* Foo::make(Pool* p)

{

return new PoolFoo(new(p) ConcreteFoo, p);

}

Такой вариант намного «чище» для клиента. Единственное место, в котором клиентский код должен знать что-то о пулах, - создание объекта функцией make(Pool*). Остальные пользователи полученного невидимого указателя понятия не имеют, находится их рабочий объект в пуле или нет.

Стековые оболочки

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

1.   Сделать Pool чисто абстрактным базовым классом с инкапсулированными производными классами, производящими функциями и т.д.

2.   Предоставить функцию static Foo::makePool(). Функция make(Pool*) будет работать и

для других разновидностей Pool, но makePool() позволяет Foo выбрать производящую

функцию Pool, оптимальную для хранения Foo (например, с передачей размера экземпляра).

3.   Переработать старый шаблон MP из предыдущих глав (с операторной функцией operator Type*()), чтобы при выходе из пула и указателей за пределы области действия все

необходимое автоматически уничтожалось.

Ниже показан примерный вид полученного интерфейса, с фрагментом клиентского кода и без виртуального оператора =.

// В файле foo.h

// Подключить объявление чисто абстрактного базового класса

#include "pool.h"

class Foo {

private:

Foo(const Foo&) {}

Foo& operator=(const Foo&) { return *this; }

public:

static Pool* makePool(); // Создать пул, оптимизированный для Foo

static Foo* make(); // Не использует пул

static Foo* make(Pool*); // Использует пул

// И т.д.

};

// Клиентский код

void g(Foo*);

void f()

{

MP<Pool> pool(Foo::makePool());

MP<Foo> foo(Foo::make(pool));

foo->MemberOfFoo(); // Использует операторную функцию operator->()

g(foo); // Использует операторную функцию operator Type*()

// Выход из области действия - удаляется сначала foo, затем pool

}


Назад    Содержание    Далее    

   Почти всегда целью создания сайта является получение прибыли, которая в свою очередь, зависит от его внешнего вида. Статистика говорит, что около 94% людей, при выборе товара, сначала обращают внимание на упаковку, а потом уже на её содержимое. И если эта упаковка не привлекательная и безвкусная, мало кто обратит на нее внимание, и, соответственно, товар не будет пользоваться спросом.
   В случае с интернет, “упаковкой” выступает ваш сайт, а “товаром” - его контент. Если сайт выглядит непривлекательно, то каким бы ценным и нужным не было его содержимое, люди будут обходить его стороной. Наша задача - сделать ваш сайт привлекательным и удобным, чтобы люди чувствовали себя уютно и комфортно, чтоб они возвращались к вам еще и еще. Соответствие между ценой и качеством вас, несомненно, порадуют.
.
   Мы делаем сайты для бизнеса, а не красочную картинку, которая увешена тяжеловесными флэшами и огромными фотографиями.
   Пользователя, когда он попадает на абсолютно любой сайт, прежде всего интересует информация, затем, как реализовать на этом сайте полученную информацию, чтобы было удобно и просто (юзабилити), подбор цветовой гаммы, расположение блоков на странице и многое другое.

   Перед тем, как заказывать создание сайта, рекомендуем прочесть статью А зачем мне (нам) сайт? или Что нужно знать заказчику сайта
Да и вообще, обратите внимание на раздел Статьи о продвижении сайта и бизнеса там вы найдёте ответы на многие вопросы.