C ++ ссылка на shared_ptr против ссылки - PullRequest
0 голосов
/ 09 октября 2009

All

Я недавно опубликовал этот вопрос о дизайне DAL. Исходя из этого, может показаться, что передача ссылки на объект в функцию с последующим заполнением этого объекта функцией будет хорошим интерфейсом для уровня доступа к данным C ++, например

  bool DAL::loadCar(int id, Car& car) {} 

Теперь мне интересно, будет ли лучше использовать ссылку на boost :: shared_ptr, например,

  bool DAL::loadCar(int id, boost::shared_ptr<Car> &car)

Есть мысли? Предлагает ли одно преимущество перед другим?

Каковы будут последствия применения константной корректности для обоих вызовов?

Заранее спасибо.

Ответы [ 4 ]

3 голосов
/ 09 октября 2009

Как говорит sbi : «Это зависит от того, что делает функция».

Тем не менее, я думаю, что наиболее важным аспектом вышеизложенного является не то, разрешено ли NULL или нет, а то, хранит ли функция указатель на объект для дальнейшего использования. Если функция просто заполняет некоторые данные, я бы использовал ссылку по следующим причинам:

  • функция по-прежнему может использоваться клиентами, которые не используют shared_ptr, используются для объектов стека и т. Д.
  • использование функции с shared_ptr все еще тривиально - shared_ptr имеет оператор разыменования, который возвращает ссылку
  • пропуск NULL невозможен
  • меньше печатать
  • Мне не нравится использовать "вещи", когда мне не нужно

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

3 голосов
/ 09 октября 2009

Зависит от того, что делает функция.

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

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

1 голос
/ 09 октября 2009

Если вы должны получить действительный объект (т.е. вы не хотите, чтобы вызывающая сторона передавала NULL), то ни в коем случае не используйте boost :: shared_ptr. Ваш второй пример передает ссылку на «умный указатель» .... игнорируя детали, это «указатель на указатель на автомобиль». Поскольку он является ссылкой, объект shared_ptr не может иметь значение NULL .... но это не значит, что он не может иметь значение NULL (т. Е. Указывать на "нулевой" объект).

Я не совсем понимаю, почему вы думаете, что ссылка на умный указатель была бы "лучше" - функция вызывающего абонента уже использует умный указатель?

Что касается значения "const" ... ты имеешь в виду что-то вроде

bool DAL::loadCar(int id, const Car& car) {}

? Если да, это будет контрпродуктивно, вы сообщаете компилятору о том, что «машина» не меняется (но, вероятно, вы хотите, чтобы она изменилась!).

Или вы хотите сделать функцию "const", что-то вроде

class DAL{
   bool loadCar(int id, Car& car) const;
}

В последнем случае вы сообщаете пользователю компилятора / API, что метод loadCar не изменяет объект DAL. Это хорошая идея, если это так - не только то, что она позволяет оптимизировать некоторые компиляторы, но и вообще хорошо указывать в «контракте» (сигнатуре функции), что функция не вносит изменений в DAL, особенно если вы делаете это неявное предположение в своем коде (таким образом вы гарантируете, что это останется верным, и что в будущем никто не изменит функцию «loadCar» таким образом, который изменит объект «DAL»)

0 голосов
/ 09 октября 2009

В первом случае вы просто передаете автомобиль и «наполняете его» информацией. Например, вы можете создать автомобиль по умолчанию, а затем заполнить его. В этом я вижу одно неудобство: не очень хорошо иметь два класса автомобилей: один плохой, по умолчанию, бесполезный, «пустой» автомобиль, и один действительно заполненный автомобиль после того, как он вышел из функции. Для меня автомобиль - это автомобиль, поэтому он должен быть действительным автомобилем (например, тем, который я могу проехать из пункта А в пункт Б; тем, который я могу разогнать, затормозить, запустить, остановить) до и после вашей функции. *

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

...