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

Вернуть ссылку const или копию в функцию геттера?

Что лучше по умолчанию, чтобы вернуть копию (1) или ссылку (2) из ​​функции getter?

class foo {
public:
    std::string str () { // (1)
        return str_;
    }

    const std::string& str () { // (2)
        return str_;
    }

private:
    std::string str_;
};

Я знаю 2) может быть быстрее, но не обязательно из-за (N) RVO. 1) более безопасен в отношении оборванных ссылок, но объект, вероятно, будет удален из жизни или ссылка никогда не будет сохранена.

Что вы делаете по умолчанию при написании класса и не знаете (еще), важны ли вопросы производительности и времени жизни?

Дополнительный вопрос: меняется ли игра, когда элемент не является простой строкой, а скорее вектором?

4b9b3361

Ответ 1

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

Ожидаете ли вы, что вызывающий абонент увидит изменения, внесенные в str_ unbeknownst (какое слово!)? Затем вам нужно передать ссылку. Может быть, хорошо, если вы можете иметь refcounted data member и вернуть это.

Если вы ожидаете, что вызывающий абонент получит копию, выполните 1).

Ответ 2

Мое правило состоит в том, чтобы вернуть копию для простых базовых типов данных, таких как int, string и т.д. Для немного более сложных структур, где копирование может быть более дорогостоящим (например, указанный вами вектор), я предпочитаю возвращать константу-ссылку.

Ответ 3

В этом случае компилятор не сможет выполнить (N) RVO. Оптимизация значений с именем (named) - это оптимизация, где компилятор создает автоматические переменные функции вместо возвращаемого значения, чтобы избежать копирования:

std::string f()
{
   std::string result;
   //...
   return result;
}

Когда компилятор видит вышеприведенный код (и полагая, что если присутствует какой-либо другой возврат, он также возвращает переменную result), он знает, что переменная result имеет как только возможную судьбу, скопированную по возвращенному временному, так и затем уничтожается. Затем компилятор может удалить переменную result и использовать возвращаемое временное значение как единственную переменную. Я настаиваю: компилятор не удаляет временное возвращение, он удаляет локальную переменную функции. Для выполнения соглашения об использовании компиляторов требуется временное возвращение.

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

Ответ 4

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

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

string s = obj.str();

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

  • Интеллектуальные указатели
  • итераторы
  • Все типы неклассов.

Ответ 5

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

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

Ответ 6

Если нет особых причин использовать тип значения в качестве возвращаемого значения, я всегда возвращаю ссылку на константу. Если мне нужна (или требуется) копия (записываемая), я добавляю копию ctor и оператор присваивания возвращенному классу, если он еще не доступен. Для использования подумайте:

const MyClass & ref = container.GetAt( 1234 ); // need only reference
MyClass copy = container.GetAt( 1234 ); // get writable copy 

На самом деле это довольно прямолинейно, не так ли?

Ответ 7

  • если его маленький базовый тип - примитивы, такие как int и long, и их обертки и другие основные вещи, такие как "Point" - вернуть копию

  • если его строка или любой другой сложный тип - возвращают ссылку.

Ответ 8

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

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