Является ли хорошей идеей всегда возвращать ссылки для получателей переменных-членов? - PullRequest
5 голосов
/ 19 сентября 2010

Если у меня есть класс, который имеет много int, float и enum переменных-членов, считается ли эффективной и / или хорошей практикой возвращать их в качестве ссылок, а не копий, и возвращать константные ссылки там, где нет изменения должны быть сделаны? Или есть причина, по которой я должен вернуть их в виде копий?

Ответы [ 7 ]

7 голосов
/ 19 сентября 2010

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

4 голосов
/ 19 сентября 2010

В некоторых случаях необходимо:

Посмотрите на перегруженный operator[] для любого класса.У него обычно есть две версии.Мутантная версия должна возвращать ссылку.

int &operator[](int index);           // by reference
int operator[](int index) const;      // by value

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

Во многих случаях ссылки обычно упрощают синтаксис, например, где 'v' - вектор STL.

v.at(1) = 2 vs *(v.at(1)) = 2;
4 голосов
/ 19 сентября 2010

Если они постоянные ссылки, возможно, все в порядке. Если они не являются постоянными ссылками, вероятно, нет.

Что касается эффективности - на 64-битной машине ссылки будут 64-битными (замаскированные указатели); int и float и enum будут меньше. Если вы возвращаете ссылку, вы заставляете уровень косвенности; это менее эффективно.

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

1 голос
/ 19 сентября 2010

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

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

0 голосов
/ 14 ноября 2012

Геттеры предназначены для выбросов класса, скажем, Exhaust Car.emit(), где автомобиль только что создал Exhaust.

Если вы обязаны написать const Seat& Car.get_front_seat()
, чтобы потом сидеть в Driver, вы сразу можете заметить, что что-то не так.
Правильно, вы бы лучше написали Car.get_in_driver(Driver)
, который затем вызывает напрямую seat.sit_into(Driver).

Этот второй метод позволяет легко избежать тех неловких ситуаций, когда вы get_front_seat закрываете дверь, и вы фактически толкаете водителя через закрытую дверь.Помните, вы только попросили место!:)

В целом: всегда возвращайте по значению (и полагайтесь на оптимизацию возвращаемого значения) или понимайте, что пришло время изменить свой дизайн.

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

Дальнейшие ловушки: в c ++, если вы возвращаете что-то с помощью const ref, то вы можете легко забыть, что это всего лишь ссылка, и как только ваш объект будет уничтожен, у вас может остаться неверный ref.В противном случае этот объект будет скопирован , как только он все равно покинет получатель.Но компилятор избегает ненужных копий, см. Оптимизация возвращаемого значения .

0 голосов
/ 19 сентября 2010

Это в основном вопрос производительности, но с точки зрения надежности я бы сказал, что лучше возвращать значения, а не константные ссылки. Причина в том, что даже константные ссылки ослабляют инкапсуляцию. Учтите это:

struct SomeClass
{
   std::vector<int> const & SomeInts () const;
   void AddAnInt (int i);  // Adds an integer to the vector of ints.
private:
   std::vector<int> m_someInts;
};

bool ShouldIAddThisInt(int i);

void F (SomeClass & sc)
{
   auto someInts = sc.SomeInts ();
   auto end = someInts.end ();
   for (auto iter = someInts.begin (); iter != end; ++iter)
   {
      if (ShouldIAddThisInt(*iter))
      {
         // oops invalidates the iterators
         sc.AddAnInt (*iter);
      }
   }  
}

Так что, если это имеет смысл с семантической точки зрения и мы можем избежать чрезмерных динамических распределений, я предпочитаю возвращение по значению.

0 голосов
/ 19 сентября 2010

Почти константные ссылки лучше.Для целых чисел и тому подобного нет никакого смысла, потому что вы хотели бы, чтобы они были изменены или потому что они имеют тот же размер (или почти), что и эталонные.Я предпочитаю другой язык или хакую свои собственные вещи на C ++ и просто позволяю var быть публичным (опять же, это просто мои собственные вещи)

...