220
Указатель на переменную класса
Идея указателя на переменную класса заключается в том, что переменную можно однозначно
идентифицировать не по
ее непосредственному адресу, но по адресу содержащего ее объекта и
смещению переменной внутри объекта. Если вы никогда не пользовались указателями на переменные
класса, изучите следующий фрагмент как можно внимательнее.
class Foo {
private:
int
x;
public:
static int& Foo::*X() { return &Foo::x; }
};
Foo f = new Foo;
// Создать экземпляр
int& Foo::*pm = Foo::X();
// Вычислить смещение int
int& i = f->*pm;
// Применить смещение к экземпляру
Функция
X()
возвращает не ссылку на
int
, а смещение некоторого
int
в экземплярах класса
Foo
.
Функция
Foo::X()
объявлена
статической, поскольку относится не к конкретному экземпляру, а к
классу в целом. Команда
return &Foo::x;
определяет смещение конкретной переменной,
x
. В строке
int& Foo::*pm = Foo::X();
объявляется переменная
pm
, которая содержит смещение переменной
int
класса
Foo
. Она инициализируется смещением, полученным от
Foo::X()
. Наконец, в строке
int&
i = f->*pm;
смещение применяется к конкретному экземпляру для вычисления адреса конкретного
int. Обратите внимание: значение pm само по себе бесполезно до тех пор, пока вы не примение его к
объекту.
Все эти
int&
с таким же успехом можно заменить на
int*
. В любом случае все завершается
косвенным получением адреса некоторой части объекта так, словно вы
получили явный адрес
переменной класса. Указатели на члены классов также могут применяться для косвенных ссылок на
функции, а не на переменные класса, но это не относится к нашей теме — управление памятью. К тому
же я не хочу взваливать на себя лишнюю головную боль.
vtable
x
y
f
pm = Foo::X()
F->*pm
Последствия
Все сказанное обладает фундаментальными последствиями для управления памятью. Чтобы
переместить объект в памяти, вам придется проследить за тем, чтобы перемещался вмещающий объект
верхнего уровня, а не некоторый вложенный объект, адрес которого у вас имеется. Более того, при
перемещении
объекта придется обновлять все указатели — не только на сам объект, но и на все
вложенные объекты и базовые классы.
Если вы хотите узнать, существуют ли ссылки на некоторый объект, придется
искать указатели не
только на начало объекта, но и на все его переменные и базовые классы.
Поиск указателей
Итак, теперь мы знаем, с какими разными указателями нам придется иметь дело. Как же отыскать их
все? Чтобы переместить объект, нам придется обновить все указатели на него. Чтобы понять, доступен
ли объект, придется собрать все указатели.
Специализированные пространства памяти для указателей
Одно из «силовых» решений — сложить все указатели в одно место, где их будет легко найти. В свою
очередь, это подразумевает, что все указатели должны быть умными и храниться в специальных
пространствах памяти. Эти пространства должны быть организованы так, чтобы вы могли перебрать их