Подтвердить что ты не робот

Что должно вернуть получателю С++

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

Какова наилучшая практика для метода getter С++, который должен возвращать нетривиальный тип, но член, который относится к типу класса или структуре.

  • Возврат по значению, например: MyType MyClass::getMyType() { return mMyType; }
  • Возврат по ссылке const: const MyType& MyClass::getMyType() { return mMyType; }
  • Возврат по адресу: MyType* MyClass::getMyType() { return &mMyType; }

где

class MyType { /* ... */ };

class MyClass
{
  private:
     MyType mMyType;
}

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

MyType* savedPointer;

SomeType function(MyType* pointer) { savedPointer = pointer; };

а. действительны для 1. и 2.

{
  MyType t = myClass.getMyType();
  function(&t);
}

// is savedPointer still valid here?

б. действительны для 1. и 2.

{
  const MyType& t = myClass.getMyType();
  function(&t);
}

// is savedPointer still valid here?

с. действительны для 1. и 2.

{
  MyType& t = myClass.getMyType();
  function(&t);
}

// is savedPointer still valid here?

д. действует для 3.

{
  MyType* t = myClass.getMyType();
  function(t);
}

// is savedPointer still valid here?

где myClass - объект типа myClass.

4b9b3361

Ответ 1

Вы можете указать как константные, так и неконстантные версии:

MyType       & MyClass::getMyType()       { return mMyType; }
MyType const & MyClass::getMyType() const { return mMyType; }

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

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

Один из вариантов заключается в том, чтобы сохранить аксессуар MyType const &, но предоставить более косвенные средства для изменения внутреннего объекта (setMyType(…) или что-то более приспособленное к семантике, которую вы пытаетесь выразить на уровне содержащего класса).

Ответ 2

В общем, вы должны предпочесть возврат по значению, если только вы явно хотят гарантировать, что ссылка будет обозначать член (который предоставляет часть вашей реализации, но желательно в таких случаях, как std::vector<>::operator[]). возврате ссылка предотвращает последующие изменения в классе, поскольку это означает, что вы не можете вернуть вычисленное значение. (Это особенно важно, если класс предназначен для базового класса, поскольку возврат ссылки создает это ограничение для всех производных классы.)

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

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

Ответ 3

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

Ответ 4

Возврат по значению, например: MyType MyClass::getMyType() { return mMyType; }, следует избегать, поскольку вы скопируете содержимое своего объекта. Я не вижу выигрыша, которого вы могли бы получить, но я вижу недостатки в производительности.

Возвращение по константной ссылке: const MyType& MyClass::getMyType() { return mMyType; } более широко используется следующим образом:

const MyType& MyClass::getMyType() const { return mMyType; }
MyType& MyClass::getMyType() { return mMyType; }

Всегда предоставляйте версию const. Версия non-const необязательна, так как это означает, что кто-то может изменить ваши данные. Это то, что я бы рекомендовал вам использовать.

Возврат по адресу: MyType* MyClass::getMyType() { return &mMyType; } в основном используется, когда данные там необязательны. Его часто нужно проверять перед использованием.

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

Для ваших примеров есть два случая:

а. savedPointer больше не действует после закрытия.

b, c и d. savedPointer действует после закрывающей скобки, но будьте осторожны, чтобы не пережить myClass.

Ответ 5

a) MyType t = создаст копию объекта как для 1, так и для 2. Сохраненный указатель будет недействительным после того, как t будет недоступен.

b) Сохраненный указатель будет действителен для случая, возвращающего ссылку, но недействительный для случая, возвращающего объект. Для ссылки время жизни указателя будет таким же, как myClass. Конечно, t на const ref был бы const t * not a t *, и поэтому не смог бы включить в ваш вызов function(MyType*).

c) То же, что и b, хотя код недействителен для 2, потому что вы не можете использовать a const MyType& для MyType&. Как правило, это была бы плохая практика, и форма const была бы более приемлемой.

d) savedPointer будет иметь такое же время жизни, что и myClass.

Я обычно склонялся к возврату ссылки или ссылки на константу в зависимости от того, что вы ожидаете от возвращаемого значения. Если вы вернете ссылку (не const), вы можете делать такие вещи, как: myClass.getMyType() = ..., а если вы вернете ссылку const, объект доступен только для чтения.