2010-01-20 6 views
3

Указатели разыменования могут сделать код очень трудным для чтения. Обычно я делаю ссылку на заостренный объект и работу со ссылкой. Пример:Ссылка на заостренный объект

shared_ptr<std::vector<int> > sp = get_sp_to_vector(); 
std::vector<int>& vec = *sp; 
... 
vec.push_back(5); 

Удивительно, если это хорошая практика. Есть ли у него недостаток?

Update: Чтобы завершить пример, я определил бы get_sp_to_vector() следующим образом:

shared_ptr<std::vector<int> > get_sp_to_vector() 
{ 
    // create a vector and send back a shared pointer pointing at it 
    shared_ptr<std::vector<int> > sp(new std::vector<int>); 
    sp->push_back(1); sp->push_back(3); 
    return sp; 
} 
+2

Я тоже это делаю. Мне кажется довольно разумным, когда у меня есть какой-то указатель, но с чем я действительно хочу работать, это то, на что он указывает. Чтобы избежать конфликтов имен между различными типами переменных, относящихся к одному и тому же значению в одной и той же области, я использую имена типа «foo» для ссылочного или фактического объекта «p_foo» для указателя «ap_foo» для 'std :: auto_ptr 'и" sp_foo "для' boost :: shared_ptr' или 'std :: tr1 :: shared_ptr'. – Wyzard

+0

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

+1

@ceretullis: Нет, в моем комментарии не рассматривается вопрос о том, есть ли у него какие-то недостатки. Вот почему я решил написать комментарий вместо ответа. – Wyzard

ответ

2

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

Это, как правило, не трудно гарантировать, но вот некоторые плохие примеры:

shared_ptr<X> p = get_p(); 
X& r = *p; 
p.reset(); // might result in destroying r 
use(r); // oops 

// or: 
shared_ptr<X> p = get_p(); 
X& r = *p; 
p = get_some_other_p(); // might result in destroying r 
use(r); // oops 
+0

shared_ptr не имеет функции release(), просто reset(), но я согласен с этим - наличие двух переменных, связанных вместе, добавляет ненулевые накладные расходы по сложности. Поскольку одна из них является ссылкой, вы даже не можете обновить r, чтобы соответствовать новому значению p. –

+0

Упс, спасибо, поскольку вы осознали, что это важно. – 2010-01-20 05:07:23

2

Я не считаю, что это хорошая практика. Указатели являются основным местом разработки C/C++ и b/c этого, кодеки C/C++ удобны с синтаксисом de-reference, необходимым для указателей. Я стараюсь избегать использования указателей, когда это возможно (не для синтаксических соображений), но иногда это просто лучший инструмент для работы. Если у вас есть код, который является gnarly b/c, вы используете указатель, я бы, как правило, де-ссылку на него в функцию, которая передает объект по ссылке, которая по существу делает то, что вы делаете, но, на мой взгляд, она делает это в более элегантный способ. Таким образом, вместо:

shared_ptr<std::vector<int> > sp = get_sp_to_vector(); 
std::vector<int>& vec = *sp; 
...ugly stuff... 
vec.push_back(5); 

Я хотел бы сделать:

void func(std::vector<int> &vec) 
{ 
    ... previously ugly stuff... 
    vec.push_back(5); 
} 

shared_ptr<std::vector<int> > sp = get_sp_to_vector(); 
func(*sp); 

EDIT:
Это не означает, что вы должны создать функцию, чтобы просто создать более хороший синтаксис для указателей, так как она является укажите, что если вам не нравится синтаксис указателя, и ваш код использует чистые и сжатые функции, вы можете просто заставить функции брать ссылки и де-ссылаться на свой указатель при вызове функции. В ситуациях, когда у вас есть только несколько вызовов на * p или p-> x, кажется глупым создать функцию со ссылкой или создать ссылку, чтобы вызвать p.x. Просто используйте синтаксис указателя в этих случаях, так как это синтаксис C/C++.

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

+3

@RC: Вы делаете то же самое ... просто скрываете его в вызове функции (что подходит в зависимости от того, какие операции будут выполняться). – paxos1977

+0

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

+0

@RC: хорошо ... +1, я покупаю это, но это не ясно в вашем ответе. Кажется, и, может быть, я просто плотный, что вы предлагаете Jabba делать рефакторинг типа метода извлечения, чтобы скрыть создание ссылки. – paxos1977

2

ИМХО, я думаю, что это приемлемая практика (с некоторыми оговорками - см Roger Pate's пост). Если вы добавляете строку кода только для вызова push_back(), я не думаю, что это приемлемо.

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

+0

+1 для упоминания о хорошем использовании, когда указатель часто ссылается на ссылки. Интересно, как часто компиляторы могут делать эту оптимизацию для вас, когда обнаруживают циклы с указателями, которые де-ссылку? Похоже, что нужно/нужно знать, сколько раз цикл будет выполнен, чтобы узнать, выгодно ли это. –

+2

Фактически, разыменование указателя в ссылку ничего не делает для производительности почти в каждом компиляторе. Под капотом ссылки в основном реализуются так же, как и указатели. –

+0

Согласен с Терри Махаффи. Однако использование ссылок на конкретные записи в массиве может сохранить повторные добавления. – rlbond

1

Если я на самом деле выполняю манипуляции с указателем, я оставляю его указателем. Если мой указатель - просто ничтожная ссылка, я оставляю его указателем. Если я уверен или хочу убедиться, что указатель всегда будет отличным от нуля (I.e., если я возвращаю объект non-nil из метода), то Я делаю это явным с помощью ссылки.

1

Работа назад из предложенного вами кода, я не согласен, что:

shared_ptr<std::vector<int> > sp = get_sp_to_vector(); 
... 
sp->push_back(5); 

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

Возможно, если ваш код указателя очень трудно прочитать, это потому, что вам не хватает трюка, который упростит его. Возможно, если вы зададите другой вопрос с примером плохого кода указателя, который вы в настоящее время исправили с помощью ссылки, SOers найдут альтернативные исправления.