Рассмотрим парадигматическую функцию шаблона 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
, которая возвращает свой результат по значению, а не по ссылке, по причине, обсуждаемой в этом вопросе?