8.8. Присвоение каждому экземпляру класса уникального идентификатора
8.8. Присвоение каждому экземпляру класса уникального идентификатора
Проблема
Требуется, чтобы каждый объект класса имел уникальный идентификатор.
Решение
Для отслеживания следующего доступного для использования идентификатора используйте статическую переменную-член. В конструкторе присвойте текущему объекту очередное доступное значение, а затем инкрементируйте статическую переменную. Чтобы понять, как это работает, посмотрите на пример 8.8.
Пример 8.8. Присвоение уникальных идентификаторов
#include <iostream>
class UniqueID {
protected:
static int nextID;
public:
int id;
UniqueID();
UniqueID(const UniqueID& orig);
UniqueID& operator=(const UniqueID& orig);
};
int UniqueID::nextID = 0;
UniqueID::UniqueID() {
id = ++nextID;
}
UniqueID::UniqueID(const UniqueID& orig) {
id = orig.id;
}
UniqueID& UniqueID::operator=(const UniqueID& orig) {
id = orig.id;
return(*this);
}
int main() {
UniqueID a;
std::cout << a.id << std::endl;
UniqueID b;
std::cout << b.id << std::endl;
UniqueID c;
std::cout << c.id << std::endl;
}
Обсуждение
Для отслеживания следующего доступного для использования идентификатора используйте статическую переменную. В примере 8.8 используется static int, но вместо нее можно использовать все, что угодно, при условии, что имеется функция, которая может генерировать уникальные значения.
В данном случае идентификаторы не используются повторно до тех пор, пока не будет достигнуто максимально возможное для целого числа значение. При удалении объекта его уникальное значение пропадает либо до перезапуска программы, либо до переполнения значения идентификатора. Эта уникальность в программе может иметь несколько интересных преимуществ. Например, при работе с библиотекой управления памятью, которая перемещает блоки памяти и обновляет значения указателей, можно быть уверенным, что для каждого объекта будет сохранено его первоначальное уникальное значение. При использовании уникальных значений в сочетании с рецептом 8.4, но применении map вместо list можно легко найти объект с заданным уникальным номером. Чтобы сделать это, просто отобразите уникальные ID на экземпляры объектов, как здесь.
static map<int, MyClass*> instmap;
Таким образом любой код, который отслеживает идентификаторы объектов, всегда сможет найти его без необходимости хранить ссылку на него.
Но это еще не все. Рассмотрим случай, когда один из этих объектов требуется добавить в стандартный контейнер (vector, list, set и т.п.). Стандартные контейнеры хранят копии объектов, добавляемых в них, а не ссылки или указатели на эти объекты (конечно, при условии, что это не контейнер указателей). Таким образом, стандартные контейнеры ожидают, что объекты, которые в них содержатся, ведут себя как объекты значений, что означает, что при присвоении с помощью оператора присвоения или копировании с помощью конструктора копирования создается новая версия, полностью эквивалентная оригинальной версии.
Это означает, что требуется решить, как должны себя вести уникальные объекты. При создании объекта с уникальным идентификатором и добавлении его в контейнер у вас появятся два объекта с одним и тем же идентификатором при условии, что вы не переопределили оператор присвоения. В операторе присвоения и конструкторе копирования требуется выполнить те действия с уникальным значением, которые имеют смысл для вашего случая. Имеет ли смысл то, что объект в контейнере будет равен оригинальному объекту? Если да, то вполне подойдет стандартный конструктор копирования и оператор присвоения, но вы должны указать это явно, чтобы пользователи вашего класса знали, что вы делаете это намеренно, а не просто забыли, как работают контейнеры. Например, чтобы использовать одно и то же значение идентификатора, конструктор копирования и оператор присвоения должны выглядеть вот так.
UniqueID::UniqueID(const UniqueID& orig) {
id = orig.id;
}
UniqueID& UniqueID::operator=(const UniqueID& orig) {
id = orig.id;
return(*this);
}
Но может возникнуть ситуация, когда в контексте приложения будет иметь смысл создать для объекта в контейнере новое уникальное значение. В этом случае просто снова используйте статическую переменную, как это сделано в обычном конструкторе и показано здесь.
UniqueID::UniqueID(const UniqueID& orig) {
id = ++nextID;
}
UniqueID& UniqueID::operator=(const UniqueID& orig) {
id = ++nextID;
return(*this);
}
Однако трудности еще не закончились. Если UniqueID будет использоваться несколькими потоками, у вас снова возникнут проблемы, так как доступ к статическим переменным не синхронизирован. За дополнительной информацией о работе с ресурсами при наличии нескольких потоков обратитесь к главе 12.
Смотри также
Рецепт 8.3.
Более 800 000 книг и аудиокниг! 📚
Получи 2 месяца Литрес Подписки в подарок и наслаждайся неограниченным чтением
ПОЛУЧИТЬ ПОДАРОКЧитайте также
Использование идентификатора UID в качестве условия
Использование идентификатора UID в качестве условия Если разрабатываемый код связан с контекстом процесса, то иногда появляется возможность выполнить альтернативную реализацию не "ломая" существующий код. Это важно, если необходимо переписать важный системный вызов и
28.1. Преобразование идентификатора в имя
28.1. Преобразование идентификатора в имя В результате выполнения команды ls -l для вывода списка содержимого текущего каталога в третьей и четвертой колонках указываются идентификаторы (ID) пользователя и группы, к которой принадлежит каждый файл. Этот список выглядит
23.8. Определение идентификатора ассоциации по IP-адресу
23.8. Определение идентификатора ассоциации по IP-адресу Модифицированный клиент из раздела 23.7 использовал уведомления в качестве сигнала для получения списков адресов. Это было достаточно удобно, поскольку идентификатор ассоциации, для которой требовалось получить
Раздел идентификатора
Раздел идентификатора Теперь поговорим о содержимом второго раздела, используемого для описания расширения.Кроме разделов идентификаторов для расширений файлов, в системе также существуют стандартные идентификаторы Windows, описывающие такие объекты, как папка, диск,
Параметры раздела идентификатора
Параметры раздела идентификатора Раздел идентификатора может содержать следующие параметры.? EditFlags — данный параметр DWORD-типа определяет различные ограничения на модификацию параметров данного расширения при помощи вкладки Типы файлов диалога Свойства папки.
Разделы ветви идентификатора
Разделы ветви идентификатора Раздел идентификатора, кроме параметров, может включать в себя и другие разделы — они определяют значок, используемый для файлов с данным расширением, текущую версию идентификатора, а также сами команды контекстного меню файла. Рассмотрим
Присвоение команд элементам меню
Присвоение команд элементам меню Выполните команду Вид ? Инспектор. В правой части рабочего окна появится панель инструментов Инспектор. На вкладке Действие этой панели (рис. 11.13) из раскрывающегося списка Тип действия можно выбрать команды, которые будут присвоены
7.1. Каждому – свой шесток
7.1. Каждому – свой шесток Один умный человек как-то сказал: «Большинство компьютерных вирусов ходит на двух ногах и пользуется двумя руками». И правда, сам пользователь может нанести компьютеру огромный урон. Вернее, раньше мог. В Vista предусмотрена довольно надежная
26.4.2. Присвоение значения имени переменной
26.4.2. Присвоение значения имени переменной Можно также поставить в соответствие полю данных имя переменной. Рассмотрим, что это означает на практике. Предположим, что в нашем распоряжении имеется следующий файл:$ pg dataPC 486 MONITOR svga NETWORK yesНам необходимо, чтобы первому столбцу
Область действия идентификатора
Область действия идентификатора Любой используемый в программе идентификатор должен быть предварительно описан. Идентификаторы описываются в разделе описаний. Идентификаторы для переменных могут также описываться внутри блока.Основная программа, подпрограмма, блок,
ИНТЕРНЕТ: Каждому свое
ИНТЕРНЕТ: Каждому свое Автор: Родион НасакинВ новогоднем номере «КТ» мы составляли рейтинги самых примечательных событий 2006 года. В своей версии хит-парада я тогда отметил первое заседание Форума по управлению Интернетом, состоявшееся в Греции. Участники мероприятия
Каждому по поиску
Каждому по поиску Автор: Янковский, РоманНаступившая эпоха Web 2.0 затронула и поисковики. Один за другим появляются различные специализированные поисковые системы (например, scholar.google.com, google.com/codesearch, koders.com и др.). В этой статье автор хотел бы поделиться впечатлениями о
Каждому – свой шесток
Каждому – свой шесток Один умный человек как-то сказал: «Большинство компьютерных вирусов ходит на двух ногах и пользуется двумя руками». И правда, пользователь может нанести компьютеру огромный урон. Вернее, раньше мог. В Vista предусмотрена довольно надежная защита от
Ноутбук — каждому школьнику?
Ноутбук — каждому школьнику? На самой большой в Германии ярмарке образования — Didacta — предлагаются многочисленные цифровые СМИиК для школьников. Целый ряд фирм специально для школьников выпускает ноутбуки, оснастка которых весьма похожа на обеспечение обычных