Если std:: max() возвращается по ссылке (как это и должно быть), может ли это привести к оборванной ссылке? - программирование
Подтвердить что ты не робот

Если std:: max() возвращается по ссылке (как это и должно быть), может ли это привести к оборванной ссылке?

Рассмотрим парадигматическую функцию шаблона max, std::max():

// From the STL

    // TEMPLATE FUNCTION _Debug_lt
template<class _Ty1, class _Ty2> inline
    bool _Debug_lt(const _Ty1& _Left, const _Ty2& _Right,
        _Dbfile_t _File, _Dbline_t _Line)
    {   // test if _Left < _Right and operator< is strict weak ordering
        if (!(_Left < _Right))
            return (false);
        else if (_Right < _Left)
            _DEBUG_ERROR2("invalid operator<", _File, _Line);
        return (true);
    }

// intermediate #defines/templates skipped 

    // TEMPLATE FUNCTION max
template<class _Ty> inline
    const _Ty& (max)(const _Ty& _Left, const _Ty& _Right)
    {   // return larger of _Left and _Right
        return (_DEBUG_LT(_Left, _Right) ? _Right : _Left);
    }

... Или в более простой форме:

template<typename T> inline
T const & max(T const & lhs, T const & rhs)
{
    return lhs < rhs ? rhs : lhs;
}

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

Однако, это не приводит к возможности оборванных ссылок, как в следующем коде?

int main()
{
    const int & max_ = ::max(3, 4);
    int m = max_; // Is max_ a dangling reference?
}

В этом случае код строит и работает отлично (VS 2010), а значение m установлено равным 4. Однако мне кажется, что max_ является обвязывающей ссылкой, поскольку жестко закодированные значения r 3 и 4 были переданы непосредственно на max, и память, выделенная для этих жестко закодированных констант rvalue, по праву может быть деактивирована к моменту достижения следующей строки кода.

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

class A
{
    friend bool operator<(A const &, A const &)
    {
        return false;
    }
};

int main()
{
    const A & a_ = ::max(A(), A());
    A a = a_; // Is a_ a dangling reference?
}

Я исправлю, что это использование max -, в котором значения r, определенные в списке аргументов вызова, передаются как аргументы - это пример потенциального "gotcha" с использованием max, неизбежный, поскольку max необходимо определить для возврата ссылки, чтобы избежать дорогостоящих копий (и избежать требования конструктора копирования)?

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

4b9b3361

Ответ 1

Да, это болтливая ссылка.

Да, это будет.

Версия, возвращающая значение, может быть полезна при условии, что вы используете ее по умолчанию, и переключитесь на ссылку в тех случаях, где она вам нужна. Если вы используете по-ссылке один по умолчанию и только переключитесь на значение по мере необходимости, тогда вам все равно выпадет фол gotcha, потому что осознание того, что вам нужно, это то же самое, что и осознание того, что вы должны были написать const A a_= ::max(A(), A());.

К сожалению, по значению один вводит новый gotcha:

A a, b, c;
mymax(a, b) = c; // assigns to temporary, not to a or b

(На самом деле, глядя на этот код, я считаю, что если вы его назовёте max_by_val, тогда вы не будете писать это).

Вы можете вернуть значение const, а некоторые люди рекомендуют, чтобы перегрузки операторов возвращались значением const. Но это вводит производительность в С++ 11:

A a, b, c;
c = constmymax(a, b); // copies from const rvalue instead of moving.

и даже в С++ 03 он предотвращает эквивалентную явную оптимизацию swap(c, constmymax(a,b)).

Ответ 2

(ответ удален) См. Herb Sutters статья GOTW о привязке ссылок const к временным файлам.

Изменить: я удалил ответ, потому что он был действительно неправильным (спасибо за то, что я это понял), поэтому все, что я оставляю, это ссылка на несколько связанную статью. Но будьте осторожны: Функция, описанная в статье, здесь не применима!