2015-04-22 2 views
0

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

Я столкнулся с библиотекой, где иногда класс будет хранить объект по ссылке, а иногда и указателем, и мне трудно понять, почему и когда использовать один над другим?

Пример:

class EventBusDemo : public Object 
{ 
private: 
    HandlerRegistration* playerMoveReg; 
}; 

class PlayerMoveEvent : public Event 
{ 
private: 
    Player& player; // Why not a pointer here? 
}; 

ответ

0

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

Так что если вы видите такой код:

class ObjectWithPointer 
{ 
private: 
    Object* object; 
}; 

Вам может понадобиться, чтобы сделать это:

void useIt(ObjectWithPointer & value) { 
    if(value.object!=NULL) { 
     doSomethingWith(*value.object); 
    } 
} 

И вы также можете сделать это:

void modifyIt(ObjectWithPointer & value) { 
    value.object!= some_object_ptr; 
} 

Однако, если у вас есть это:

class ObjectWithRef 
{ 
private: 
    Object& object; 
}; 

Первый пример становится:

void useIt(ObjectWithRef & value) { 
    doSomethingWith(value.object); 
} 

И в наивную преобразование от второго

void modifyIt(ObjectWithRef & value) { 
    value.object=some_object; 
} 

делает что-то совершенно другое - он копирует значение some_object в ссылку, но нет способа заставить ссылку указывать в другом месте.

+0

Объект, на который ссылается объект, может быть изменен? player.setX (п); изменит этот объект, переданный по ссылке (в конструкторе PlayMoveEvent)? –

+0

@ JakeM обновил код, чтобы уточнить, что происходит с эталонным объектом. Вы не можете изменить точку отсчета, но вы можете изменить значения внутри этой ссылки. –

0

Лучший вопрос: «Почему вы использовали указатель вместо ссылки?». Как правило, вы должны использовать указатель, только когда можете ответить на этот вопрос.

Для ссылки на что-то указатель требует немного более громоздкого синтаксиса для использования. Кроме того, вы можете сделать больше с указателем, чем вы можете, с ссылкой, например, смену, где оно указывает, что является плохим, если вы на самом деле ничего не делаете. Любой здравомыслящий читатель, который видит ваш указатель, будет вынужден рассматривать всевозможные вещи, которые они не будут делать, если бы вы использовали ссылку, например, удивлялись, если вы запомнили ее инициализацию, или задаетесь вопросом, измените ли вы то, на что оно указывает, и так далее ,

Возможно, это также затрудняет оптимизацию компилятора, поскольку компилятор должен задаться вопросом о тех же вещах!

+0

Есть также вопрос ясности. Для вызывающего не сразу становится очевидным, что они передаются по ссылке, а не по значению, а не без проверки определения функции. Если они передают указатель, они сразу знают, что функция получает доступ к исходному объекту, и с ним может случиться множество вещей.Общим соглашением, которое я видел, является передача только постоянной ссылкой (const obj & o), если вам просто нужна ссылка и не будет изменять исходный объект, а указателем в противном случае. Я не уверен, что это хорошая конвенция, но это еще одно соображение. –

0

Если вы видите в классе Xreference to object вместо указателей, X может быть приятно думать, что объект local. Это где-то в стеке. X не нужно думать о его разрушении definitely. С указателями объект будет находиться в куче. Программист (и особенно сторонник X) может запутаться в том, кто освободит этот указатель. Итак, спокойствие со ссылками. Эта точка действительна при сравнении reference-to-object-on-heap и pointer-to-object-on-stack.

Наступает другая проблема, dangling references and dangling pointers.

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

Если у вас есть болтливая ссылка, в дизайне что-то не так. Поскольку вы храните объект Y в ссылке X. X использует Y. Однако время жизни X больше, чем Y. Это может произойти, когда Y является локальным, а X является глобальным. Это противоречит интуиции, потому что, если бы в стеке вы сохранили ссылку на объект верхнего стека в объекте lower-stack-object. Но с оборванными указателями может быть неправильная ошибка логики или несоответствие владения. Итак, если проблема, такая как оборванная ссылка, может быть исправлена ​​с лучшим дизайном.

Однако, если мы храним объект в куче в качестве ссылки, было бы трудно найти проблему с обвязывающей ссылкой снова.

Итак, мой приоритет будет:

references to stack object > references to heap object > pointers. 

Глядя на ваш код и гадать: EventBusDemo, как какую-то глобальную шина, которая хранит регистрационный-обработчик, который будет называться. Здесь это один объект, и с течением времени вы будете давать ему разные playerMoveReg. Таким образом, это указатель.

PlayerMoveEvent похоже, что он был бы обработан в ближайшее время, так как это Event. Вы должны создать новый PlayerMoveEvent для нового события. Итак, вы хотите сделать player указателем или ссылкой. Вы хотите изменить player в случае (даже по ошибке)? Точно нет. Вы хотите какой-то ум? Определенно да. Итак, используйте ссылку.

0

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

0

Если вы используете указатель затем:

void PlayerMoveEvent::Foo() 
{ 
    // can it be null? its possible because its a pointer! 
    if (player) player->bar(); 
} 

PlayerMoveEvent::~PlayerMoveEvent() 
{ 
    // crash? or memory leak with out? 
    delete player; 
} 

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