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

Зачем использовать функцию, а не ссылку на участника?

Я просто тестировал какой-то код и заметил нечто похожее на:

template<typename T>
class example{
    public:
        example(T t): m_value{t}{}

        const T &value = m_value;

    private:
        T m_value;
};

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

template<typename T>
class example{
    public:
        example(T t): m_value{t}{}

        const T &value() const{
            return m_value;
        }

    private:
        T m_value;
};

Почему первый способ менее распространен? Каковы недостатки?

4b9b3361

Ответ 1

Есть несколько причин, почему (встроенные) функции, которые возвращают соответствующую ссылку, лучше:

  • Для ссылки требуется память (обычно такая же сумма, как указатель) в каждом объекте

  • Ссылки обычно имеют такое же выравнивание, как и указатели, что приводит к тому, что окружающий объект потенциально требует более высокого выравнивания и, таким образом, тратит еще больше памяти

  • Инициализация ссылки требует (минимальное количество) времени

  • Наличие поля типа ссылки может отключить копирование по умолчанию и переместить операторы присваивания, поскольку ссылки не являются пересаживаемыми

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

  • Функции могут выполнять дополнительную проверку, например, проверку инвариантов в отладочных сборках

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

Ответ 2

Герметизация.

Для пуристов с объектно-ориентированным программированием m_value является детальностью реализации. Потребители класса example должны иметь возможность использовать один надежный интерфейс для доступа к value() и не должны зависеть от того, как example может его определить. Будущая версия example (или сложная специализированная специализация) может захотеть использовать кеширование или протоколирование перед возвратом value(); или может потребоваться рассчитать value() "на лету" из-за ограничений памяти.

Если вы не используете функцию доступа раньше, все, что использует example, возможно, изменится, если вы передумаете позже. И это может ввести все виды отходов и ошибок. Легче просто отвлечь его на один уровень дальше, предоставив аксессуар, например value().

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

Ответ 3

Первый параметр требует дополнительной памяти, как указатель.

Если вы выполните:

inline const T& value() const{
      return m_value;
}

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

Кроме того, поскольку для первого подхода требуется С++ 11, будет менее вероятно, что люди его используют.

Ответ 4

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

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

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

template<typename T>
struct example {
    example(T t): value{t}{}
    union{
        const T value;
        struct{
        private:
            T value;
            friend class example<T>;
        } _value;
    };
};