Можно ли безопасно и переносимо использовать указатели в качестве идентификаторов объектов? - PullRequest
8 голосов
/ 20 июня 2011

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

Ответы [ 9 ]

8 голосов
/ 20 июня 2011

Конечно; Я не понимаю, почему нет.

Адрес памяти - это в значительной степени определение идентичности объекта (на мгновение вычеркивая тип из уравнения).

5 голосов
/ 20 июня 2011

Не обязательно - это зависит от того, как вы распределяете эти экземпляры и что вы затем делаете с ними. Например, предположим, что вы создаете массив объектов, а затем перераспределяете этот массив. Теперь нет гарантии, что объекты будут по-прежнему находиться в том же месте.

4 голосов
/ 20 июня 2011

Хотя обычно верно, что адрес памяти однозначно идентифицирует объект. Есть два важных предостережения:

  1. Когда объект удаляется, адрес может использоваться повторно (очень возможно для объекта того же класса).

  2. Если вы работаете с разными процессами, адреса могут быть одинаковыми в обоих процессах.

4 голосов
/ 20 июня 2011

Это можно сделать только в том случае, если вы уверены, что ни один объект не будет создан после удаления объекта.Новый объект может быть создан по тому же адресу, что и ранее удаленный объект, и это может быть проблемой: вы не хотите, чтобы два разных объекта имели одинаковый идентификатор.

2 голосов
/ 20 июня 2011

Одно беспокойство (и это настоящее беспокойство) - это указатели кукушки.

Предположим, вы кэшируете значение указателя A.

Затем освободите этот указатель, затем выделите новый объект B.

Распределитель памяти может выбрать местоположение, которое использовалось для A для выделения B.

Код формы: if (new_pointer! = old_pointer) {...}

может не понять, что объект изменился.

http://www.nobugs.org/blog/archives/2004/11/20/cuckoo-pointers/

Edit:

Иначе говоря, ваш объект при жизни всегда будет находиться по тому же адресу, однако объект по этому адресу не всегда будет ожидаемым вами объектом.

2 голосов
/ 20 июня 2011

Пока объект остается в памяти и вы всегда ссылаетесь на один и тот же экземпляр (например, вы не передаете его по значению, а затем сравниваете этот объект с оригинальной или другой кэшированной копией), адрес всегда будет оставаться прежним и указатель является разумным идентификатором. Это очевидно верно - если объект перемещается в памяти, указатель больше не будет работать, и стандарт гарантирует, что указатели на разные объекты сравниваются с разными значениями. [Вот почему у вас не может быть объектов нулевой длины, поэтому следующий объект в памяти имеет другой адрес.]

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

ETA: ужасно правильно, что если вы перераспределите память, содержащую объекты, значения будут другими, но очевидно, что указатели не будут действительны вообще, поэтому ваша программа будет повреждена, если вы ожидаете, что указатели будут уникальными или нет. (И наоборот, если вы используете умные точки, которые будут отслеживать реакционные локаторы - по сути, как работают C # и .NET - значение не обязательно будет одинаковым, но значения указателей все равно будут разными в разных экземплярах объекта.) На самом деле, это правило - пока указатели действительны, вы должны иметь возможность сравнивать их, но вы не можете кешировать значение и ожидать, что оно будет работать какое-то неопределенное время спустя (в случае, если вы сначала уничтожите объект ), поэтому, если вы уверены, что этого не произойдет, это нормально, но имейте это в виду, часто вам захочется сериализовать объекты в какой-то момент, и тогда лучше спроектировать их с самого начала.

1 голос
/ 27 декабря 2011

Если указатели на разные подклассы не c-приведены к void *, тогда да, нет проблем со сравнением указателей для проверки, является ли это один и тот же объект.

В случае сохранения адреса как значения void * или uint для идентификаторов, существует несколько менее очевидных проблем, возникающих, когда класс наследуется от нескольких классов.

Рассмотрим класс C, который наследуется от класса A и класса B. Если на класс C ссылаются через указатель класса A, он будет выглядеть равным ссылке на тот же объект через указатель класса B.

C* c = new C();
A* a = C;
B* b = C;
a == b; // true

Однако, если вы приведете объект C из указателя класса A к указателю void, вы можете получить адрес вспомогательного объекта, а не полный адрес объекта. Типы будут отслеживать это в обычном случае, и это беспокоит только использование пустых указателей.

void* avoid = (void*)a;
void* bvoid = (void*)b;
avoid == bvoid; // false

Чтобы гарантировать правильный адрес для самого производного и полного объекта, используйте dynamic_cast (myObject). Помните, однако, что это должен быть полиморфный класс, и RTTI должен быть включен для работы dynamic_cast.

0 голосов
/ 19 ноября 2014

Просто вернувшись на секунду, кто-то сказал, что полиморфизм предполагает наличие нескольких адресов для одного объекта?

Я почти уверен, что именно для этого предназначена таблица виртуальных функций.Перед вызовом Object1->func1() тип и адрес Object1 используются в качестве ключей для vtable, и получается адрес для func1().Правильно?Выполнение преобразования, например, обратно в базовый класс, например:

BaseClass* OPtr = reinterpret_cast<BaseClass*>(DerivedObjectPtr);
OPtr->func1();

сделает пару ключей address + type другой и, таким образом, может вернуть разные указатели функций.

То естькак бы я написал вещи во время выполнения в любом случае.Не знаю о множественном наследовании, хотя это мерзость имо.И я также использую адреса объектов как ID s.Я не могу найти в этом никакой ошибки, может кто-нибудь еще?

0 голосов
/ 20 июня 2011

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...