Когда предпочтительно хранить элементы данных в качестве ссылок, а не указателей? - PullRequest
10 голосов
/ 05 июня 2009

Допустим, у меня есть объект Employee_Storage, который содержит элемент данных подключения к базе данных. Этот элемент данных должен храниться как указатель или как ссылка?

  • Если я сохраню его в качестве справки, я не нужно ничего делать NULL проверка. (Насколько важна проверка NULL в любом случае?)

  • Если я сохраню его как указатель, это проще в настройке Employee_Storage (или MockEmployee_Storage) для Цели тестирования.

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

Есть ли хорошее эмпирическое правило, которому нужно следовать, , особенно с точки зрения тестируемости?

Ответы [ 5 ]

14 голосов
/ 05 июня 2009

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

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

8 голосов
/ 05 июня 2009

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

См. Этот вопрос Стоит ли предпочесть указатели или ссылки в данных участника? для более подробного обсуждения вопроса.

3 голосов
/ 22 декабря 2012

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

#include <iostream>
using namespace std;
class stuff
{
public:
explicit stuff(int &a):x(a) //you have to initialize it here
{
//body intialization won't work
};
int& x; //reference data member
};

int main()
{
int A=100; 
stuff B(A);//intialize B.x
cout<<B.x<<endl;//outputs 100
A=50;//change A;
cout<<B.x<<endl; //outputs 50, so B.x is an alias of A.
system("pause");
return 0;
}
2 голосов
/ 05 июня 2009

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

Foo& m_foo;

член, а не

Foo*const m_foo;

member, поскольку в предыдущей декларации задокументирован тот факт, что m_foo не может быть нулевым. В краткосрочной перспективе преимущество не так велико. Но в долгосрочной перспективе, когда вы возвращаетесь к старому коду, мгновенная уверенность в том, что вам не нужно беспокоиться о том, что m_foo будет нулевым, весьма ценна.

Существуют и другие способы достижения аналогичного эффекта. Один проект, над которым я работал, где они не понимали ссылок, требовал суффикса любых потенциально нулевых указателей «00», например, m_foo00. Интересно, что boost::optional кажется ссылками на поддержку , хотя я не пробовал. Или вы можете засорять свой код утверждениями.

0 голосов
/ 08 сентября 2018

Добавление к этому вопросу ..

Класс с элементом справочных данных:

  • Вы должны передать значение объекту при строительстве (не случайно)
  • нарушает правило инкапсуляции, так как указанная переменная может быть изменена извне класса без какого-либо контроля над объектом класса. (Я полагаю, что единственным вариантом использования может быть что-то вроде этого, по некоторым очень специализированным причинам.)
  • предотвращает создание оператора присваивания. Что вы собираетесь скопировать?
  • вам нужно убедиться, что указанная переменная не уничтожена, пока ваш объект жив
...