Чтение онлайн

на главную - закладки

Жанры

Эффективное использование C++. 55 верных способов улучшить структуру и код ваших программ

Майерс Скотт

Шрифт:

Конечно, это только пример. От компилятора не требуется реализовывать схему именно таким образом, хотя многие так и делают.

Когда вы используете оператор delete для указателя, как он может узнать, что где-то имеется информация о размере массива? Только от вас. Если после delete стоят квадратные скобки, то предполагается, что указатель указывает на массив. В противном случае компилятор считает, что это указатель

на отдельный объект:

std::string *stringPtr1 = new std::string;

std::string *stringPtr2 = new std::string[100];

...

delete stringPtr1;

delete[]stringPtr2;

Что произойдет, если использовать форму «[]» с stringPtr1? Результат не определен, но вряд ли он будет приятным. В предположении, что память организована, как в приведенной выше схеме, delete сначала прочитает размер массива, а затем будет вызывать деструкторы, не обращая внимания на тот факт, что память, с которой он работает, не только не является массивом, но даже не содержит объектов того типа, для которых должны быть вызваны деструкторы.

Что случится, если вы не используете форму «[]» для stringPtr2? Неизвестно, но можно предположить, что будет вызван только один деструктор, хотя нужно было вызвать несколько. Более того, это не определено даже для встроенных типов, подобных int, несмотря на то что у них нет деструкторов.

Правило простое: если вы используете [] в выражении new, то должны использовать [] и в соответствующем выражении delete. Если вы не используете [] в new, то не надо использовать его в соответствующем выражении delete.

Это правило особенно важно помнить при написании классов, содержащих указатели на динамически распределенную память, в которых есть несколько конструкторов, поскольку в этом случае вы должны использовать одинаковую форму new во всех конструкторах для инициализации членов-указателей. Если этого не сделать, то как узнать, какую форму delete применить в деструкторе?

Данное правило для тех, кто часто прибегает к использованию typedef, поскольку из него следует, что автор typedef должен документировать, какую форму delete применять для удаления объектов типа, описываемого typedef. Рассмотрим пример:

typedef std::string AddressLines[5]; // адрес человека состоит из 4 строк,

// каждая из которых имеет тип string

Поскольку AddressLines – массив, то следующему применению new

std::string *pal = new AddressLines; // отметим, что “new AddressLines”

// вернет string *, как и

// выражение “new string[4]”

должна соответствовать форма delete для массивов:

delete pal; //
не определено!

delete[] pal; // правильно

Чтобы избежать путаницы, старайтесь не примененять typedef для определения типов массивов. Это просто, потому что стандартная библиотека C++ (см. правило 54) включает шаблонные классы string и vector, позволяющие практически полностью избавиться от динамических массивов. Так, в примере выше AddressLines можно было бы определить как вектор строк: vector<string>.

Что следует помнить

• Если вы используете [] в выражении new, то должны применять [] и в соответствующем выражении delete. Если вы не используете квадратные скобки [] в выражении new, то не должны использовать их и в соответствующем выражении delete.

Правило 17: Помещение в «интеллектуальный» указатель объекта, вьщеленного с помощью new, лучше располагать в отдельном предложении

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

int priority;

void processWidgets(std::tr1::shared_ptr<Widget> pw, int priority);

Помня о премудростях применения объектов, управляющих ресурсами (см. правило 13), processWidgets использует «интеллектуальный» указатель (здесь – tr1::shared_ptr) для обработки динамически выделенного объекта. Рассмотрим теперь такой вызов processWidgets:

processWidgets(new Widget, priority);

Стоп, не надо его рассматривать! Он не скомпилируется. Конструктор tr1::shared_ptr, принимающий указатель, объявлен с ключевым словом explicit, поэтому не происходит неявного преобразования из типа указателя, возвращенного выражением «new Widget», в тип tr1::shared_ptr, которого ожидает функция process-Widgets. Однако следующий код компилируется:

processWidgets(std::tr1::shared_ptr<Widget>(new Widget), priority);

Как это ни странно, но несмотря на использование управляющего ресурсами объекта, здесь возможна утечка ресурсов. Разберемся, почему.

Прежде чем компилятор сможет сгенерировать вызов processWidgets, он должен вычислить аргументы, переданные ему в качестве параметров. Второй аргумент – просто вызов функции priority, но первый – (std::tr1::shared_ptr<Widget> (new Widget)) – состоит из двух частей:

• выполнение выражения «new Widget»;

• вызов конструктора tr1::shared_ptr.

Поделиться:
Популярные книги

Инцел на службе демоницы 1 и 2: Секса будет много

Блум М.
Инцел на службе демоницы
Фантастика:
фэнтези
5.25
рейтинг книги
Инцел на службе демоницы 1 и 2: Секса будет много

Весь цикл «Десантник на престоле». Шесть книг

Ланцов Михаил Алексеевич
Десантник на престоле
Фантастика:
альтернативная история
8.38
рейтинг книги
Весь цикл «Десантник на престоле». Шесть книг

Предатель. Цена ошибки

Кучер Ая
Измена
Любовные романы:
современные любовные романы
5.75
рейтинг книги
Предатель. Цена ошибки

Жандарм 2

Семин Никита
2. Жандарм
Фантастика:
попаданцы
альтернативная история
аниме
5.00
рейтинг книги
Жандарм 2

Прогрессор поневоле

Распопов Дмитрий Викторович
2. Фараон
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Прогрессор поневоле

Всемирная энциклопедия афоризмов. Собрание мудрости всех народов и времен

Агеева Елена А.
Документальная литература:
публицистика
5.40
рейтинг книги
Всемирная энциклопедия афоризмов. Собрание мудрости всех народов и времен

Истребитель. Ас из будущего

Корчевский Юрий Григорьевич
Фантастика:
боевая фантастика
попаданцы
альтернативная история
5.25
рейтинг книги
Истребитель. Ас из будущего

Очешуеть! Я - жена дракона?!

Амеличева Елена
Фантастика:
юмористическая фантастика
5.43
рейтинг книги
Очешуеть! Я - жена дракона?!

Отмороженный 4.0

Гарцевич Евгений Александрович
4. Отмороженный
Фантастика:
боевая фантастика
постапокалипсис
рпг
5.00
рейтинг книги
Отмороженный 4.0

Треугольная шляпа. Пепита Хименес. Донья Перфекта. Кровь и песок.

Бласко Висенте Ибаньес
65. Библиотека всемирной литературы
Проза:
классическая проза
5.00
рейтинг книги
Треугольная шляпа.
Пепита Хименес.
Донья Перфекта.
Кровь и песок.

Измена. Жизнь заново

Верди Алиса
1. Измены
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Измена. Жизнь заново

Три `Д` для миллиардера. Свадебный салон

Тоцка Тала
Любовные романы:
современные любовные романы
короткие любовные романы
7.14
рейтинг книги
Три `Д` для миллиардера. Свадебный салон

Бастард Императора. Том 5

Орлов Андрей Юрьевич
5. Бастард Императора
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Бастард Императора. Том 5

Идеальный мир для Лекаря 21

Сапфир Олег
21. Лекарь
Фантастика:
фэнтези
юмористическое фэнтези
аниме
5.00
рейтинг книги
Идеальный мир для Лекаря 21