56. Обеспечьте бессбойную функцию обмена
56. Обеспечьте бессбойную функцию обмена
Резюме
Обычно имеет смысл предоставить для класса функцию swap в целях эффективного и бессбойного обмена внутреннего содержимого объекта с внутренним содержимым другого объекта. Такая функция может пригодиться для реализации ряда идиом, от простого перемещения объектов до реализации присваивания, легко обеспечивающего функцию принятия результатов работы со строгими гарантиями безопасности для вызывающего кода (см. также рекомендацию 51).
Обсуждение
Обычно функция swap выглядит примерно следующим образом (здесь U — некоторый пользовательский тип):
class T { // ...
public:
void swap(T& rhs) {
member1_.swap(rhs.member1_);
std::swap(member2_, rhs.member2_);
}
private:
U member1_;
int member2_;
};
Для примитивных типов и стандартных контейнеров можно использовать std::swap. Другие классы могут реализовывать обмен в виде функций-членов с различными именами.
Рассмотрим использование swap для реализации копирующего присваивания посредством копирующего конструктора. Приведенная далее реализация оператора operator= обеспечивает строгую гарантию (см. рекомендацию 71), хотя и ценой создания дополнительного объекта, что может оказаться неприемлемым, если имеется более эффективный способ выполнения безопасного присваивания объектов типа T:
T& T::operator=(const T& other) { // Вариант 1 (традиционный)
T temp(other);
swap(temp);
return *this;
}
T& T::operator=(T temp) { // Вариант 2 (см. рекомендацию 27)
swap(temp); // Обратите внимание на передачу
return *this; // temp по значению
}
Но что если тип U не имеет бессбойной функции обмена, как в случае многих существующих классов, но вам требуется поддержка функции обмена для типа T? Не все потеряно.
• Если копирующий конструктор и оператор копирующего присваивания U не дают сбоев, то с объектами типа U вполне справится std::swap.
• Если копирующий конструктор U может давать сбой, вы можете хранить (интеллектуальный) указатель на U вместо непосредственного члена. Указатели легко обмениваются. Следствием их применения являются дополнительные расходы на одно динамическое выделение памяти и дополнительную косвенность при обращении, но если вы храните все такие члены в едином Pimpl-объекте, то для всех закрытых членов дополнительные расходы вы понесете только один раз (см. рекомендацию 43).
Никогда не пользуйтесь трюком реализации копирующего присваивания посредством копирующего конструирования с использованием непосредственного вызова деструктора и размещающего new, несмотря на то, что такой трюк регулярно "всплывает" в форумах, посвященных С++ (см. также рекомендацию 99). Так что никогда не пишите:
T& T::operator=(const T& rhs) { // Плохо: анти-идиома
if (this != &rhs) {
this->~T(); // плохая методика!
new(this) T(rhs); // (см. [Sutter00] §41)
}
return *this;
}
Если объекты вашего типа можно обменять более эффективным способом, чем грубое присваивание, желательно предоставить функцию обмена, не являющуюся членом, в том же пространстве имен, где находится и ваш тип (см. рекомендацию 57). Кроме того, подумайте о специализации std::swap для ваших собственных нешаблонных типов:
namespace std {
template<> void swap(MyType& lhs, MyType& rhs) {
lhs.swap(rhs); // Для объектов MyType используется
} // MyType::swap
}
Стандарт не позволяет вам сделать это, если MyType сам является шаблонным классом. К счастью, иметь такую специализацию хорошо, но не обязательно; основная методика состоит в обеспечении функции swap, эффективно работающей с данным типом, в виде функции, не являющейся членом класса, в том же пространстве имен, в котором находится и ваш тип.
Исключения
Обмен важен для классов с семантикой значения. Существенно менее важна она для базовых классов, поскольку эти классы в любом случае используются посредством указателей (см. рекомендации 32 и 54).
Ссылки
[C++03] §17.4.3.1(1) • [Stroustrup00] §E.3.3 • [Sutter00] §12-13, §41
Более 800 000 книг и аудиокниг! 📚
Получи 2 месяца Литрес Подписки в подарок и наслаждайся неограниченным чтением
ПОЛУЧИТЬ ПОДАРОКЧитайте также
function - Создает новую функцию
function - Создает новую функцию functionОпределяет набор операторов, которые вы определили для выполнения определенной задачи. Вы можете декларировать (declare), или определить (define), функцию в том же месте, где вы ее вызываете, или в любом другом месте муви-клипа. При определении
Буфер обмена
Буфер обмена Буфер обмена – это специальная область оперативной памяти компьютера, в которой хранятся данные, предназначенные для перемещения или копирования как между окнами разных приложений, так и в одном и том же окне.В любой программе при выполнении команды
8.15. Эхо-сервер TCP и UDP, использующий функцию select
8.15. Эхо-сервер TCP и UDP, использующий функцию select Теперь мы объединим наш параллельный эхо-сервер TCP из главы 5 и наш последовательный эхо-сервер UDP из данной главы в один сервер, использующий функцию select для мультиплексирования сокетов TCP и UDP. В листинге 8.14 представлена
30.12. Сервер с предварительным порождением потоков: основной поток вызывает функцию accept
30.12. Сервер с предварительным порождением потоков: основной поток вызывает функцию accept Последняя рассматриваемая нами версия сервера устроена следующим образом: главный поток создает пул потоков при запуске сервера, после чего он же вызывает функцию accept и передает
Отклик на единичную функцию
Отклик на единичную функцию Единичная ступенчатая функция показана на рис. 5.20, б. По определению она остается нулевой до t=0, а начиная с этого момента становится равной 1 В. Параметры элементов для схемы, показанной на рис. 5.20, a: R=2 Ом, R1=1 Ом и С=0,125 Ф. Анализ схемы показывает,
R.18.3.4 Приведение указателей на функцию-член
R.18.3.4 Приведение указателей на функцию-член Указатель на функцию-член некоторого объекта можно привести к указателю на какую-то другую функцию, например (int (*) ())p-›f. Результирующий указатель будет настроен на функцию, вызов которой будет происходить с помощью обращения к
3.4. Буфер обмена
3.4. Буфер обмена При вырезании или копировании содержимое ячейки помещается в буфер обмена и становится доступным не только для работы в Word. Аналогично вы можете вставить в документ Word текст или иные данные, скопированные из другого приложения, с интернет,страницы и др.
Шаг 25 - Как сделать виртуальной свободную функцию.
Шаг 25 - Как сделать виртуальной свободную функцию. Чаще всего этот прием я видел в отношении оператора operator‹‹. Точнее, не чаще, а всегда. На нем и разберем. Пусть у нас есть иерархия классов, и мы хотим определить диагностическую функцию Dump(). Она должна вываливать
Совет 28. Научитесь использовать функцию base
Совет 28. Научитесь использовать функцию base При вызове функции base для итератора reverse_iterator будет получен «соответствующий» iterator, однако из сказанного совершенно не ясно, что же при этом происходит. В качестве примера рассмотрим следующий фрагмент, который заносит в вектор
Буфер обмена
Буфер обмена ChangeClipboardChain Функция ChangeClipboardChain удаляет указанное окно из цепочки просмотра буфера обмена. BOOL ChangeClipboardChain ( HWND hWndRemove , HWND hWndNewNext ); Параметры hWndRemove - дескриптор окна, которое будет удалено из цепочки. Дескриптор должен был быть передан в функцию SetClipboardViewer. hWndNewNext
7.9.1. Тип указателя на функцию
7.9.1. Тип указателя на функцию Как объявить указатель на функцию? Как выглядит формальный параметр, когда фактическим аргументом является такой указатель? Вот определение функции lexicoCompare(), которая сравнивает две строки лексикографически:#include stringint lexicoCompare( const string sl, const
Буфер обмена
Буфер обмена Просмотр буфера обмена Пример на основе простого модуля-класса, осуществляющего просмотр буфера обмена.unit ClipboardViewer;interfaceuses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;type TForm1 = class(tform) procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject);private FNextViewerHandle : THandle; procedure
Резюме: Обеспечьте финансирование обучения
Резюме: Обеспечьте финансирование обучения Обучение является клеем, скрепляющим все части программы обеспечения безопасности. Это довольно дешевый клей. К сожалению, руководители часто забывают сравнить стоимость обучения безопасности со стоимостью «уборки» после
Тактика № 1: обеспечьте свою анонимность
Тактика № 1: обеспечьте свою анонимность Прямой маркетинг зависит от возможности находить цели – от возможности продавца идентифицировать, кто вы и что вы, скорее всего, купите. Одним из способов защитить себя от маркетинговой машины является защита вашей