考虑范例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);
}
Run Code Online (Sandbox Code Playgroud)
......或者,以更简单的形式:
template<typename T> inline
T const & max(T const & lhs, T const & rhs)
{
return lhs < rhs ? rhs : lhs;
}
Run Code Online (Sandbox Code Playgroud)
我理解为什么max
模板必须通过引用返回(以避免昂贵的副本并避免复制构造函数的要求).
但是,这不会导致悬挂引用的可能性,如下面的代码所示?
int main()
{
const int & max_ = ::max(3, 4);
int m = max_; // Is max_ a dangling reference?
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,代码生成并运行正常(VS 2010)和值m
设置为4.但是,这让我感到max_
是因为硬编码的右值悬空参考3
,并4
直接传递给max
,将它们的存储分配在到达下一行代码时,可以正确地解除分配硬编码的右值常量.
我可以为完全成熟的对象设想类似的边缘情况,例如
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?
}
Run Code Online (Sandbox Code Playgroud)
我是否正确使用max
- 在调用参数列表中定义的rvalues作为参数传递 - 是一个使用的潜在"gotcha"的示例max
,不可避免,因为max
需要定义为返回引用以避免昂贵的副本(并避免复制构造函数的要求)?
max
对于这个问题中讨论的原因,可能存在现实情况,在这种情况下,定义一个版本的返回结果的价值而不是引用将是一个好的编程实践吗?
Ste*_*sop 15
是的,这是一个晃来晃去的参考.
是的,这是一个问题.
如果您默认使用它,则按值返回的版本可能很有用,并且在您需要的情况下切换到by-reference.如果你默认使用by-reference,并且只在你需要时切换到by-value,那么你仍然会犯下这个问题,因为意识到你需要它就像意识到你应该写的一样const A a_= ::max(A(), A());
.
不幸的是,按价值的一个引入了新的问题:
A a, b, c;
mymax(a, b) = c; // assigns to temporary, not to a or b
Run Code Online (Sandbox Code Playgroud)
(实际上,看看这段代码,我认为如果你打电话给它,max_by_val
那么你就不会写这个).
你可以通过const值返回,有些人曾经建议运算符重载应该返回const值.但这引入了C++ 11中的性能问题:
A a, b, c;
c = constmymax(a, b); // copies from const rvalue instead of moving.
Run Code Online (Sandbox Code Playgroud)
甚至在C++ 03中它也阻止了等效的显式优化swap(c, constmymax(a,b))
.