如果std::max()通过引用返回(这是必须的),这是否会导致悬空引用
If std::max() returns by reference (as it must), might that lead to a dangling reference?
考虑典型的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_
是一个悬空的引用,因为硬编码的右值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?
}
max
的这种用法——在调用参数列表中定义的右值作为参数传递——是使用max
的潜在"gotcha"的一个例子,这是不可避免的,因为max
需要定义为返回引用,以避免昂贵的副本(并避免副本构造函数的要求)?
在现实生活中,出于本问题中讨论的原因,定义一个通过值而不是引用返回结果的max
版本是否是一种良好的编程实践?
是的,它是一个悬空引用。
是的,我明白了。
按值返回的版本可能很有用,前提是您默认使用,并在需要的情况下切换到按引用。如果您默认使用按引用版本,并且只在需要时切换到按值版本,那么您仍然会陷入困境,因为意识到您需要它与意识到您应该编写const A a_= ::max(A(), A());
是一样的。
不幸的是,按价值计算的一个引入了一个新的陷阱:
A a, b, c;
mymax(a, b) = c; // assigns to temporary, not to a or b
(事实上,看看这个代码,我想如果你把它叫做max_by_val
,那么你就不会写这个了)。
您可以按const值返回,有些人曾经建议运算符重载应按const返回。但这在C++11中引入了一个性能难题:
A a, b, c;
c = constmymax(a, b); // copies from const rvalue instead of moving.
并且即使在C++03中它也阻止了等价的显式优化CCD_ 15。
- 存储对(可能)临时对象的引用是否合法,只要引用不比对象存活?
- 对静态分配的子类对象进行静态分配的纯虚拟父类引用是否合法?
- 形成对对象的引用是否构成访问?
- C++ 引用是否在需要时隐式转换为值?
- 右值引用是否具有与右值引用相同的开销?
- 返回引用是否也会延长其生存期?
- 返回对局部变量的引用是否正常工作?
- 右值引用是否像右值引用一样工作
- 强制转换为指针引用是否会导致未定义的行为
- C++ 指向类的指针和/或引用是否被认为是"movable"?
- 结构化绑定和转发引用是否混合良好?
- 此常量引用是否保留了其生命?
- 返回对私有向量成员元素的非常量引用是否是一种不好的做法
- 从 r 值引用限定方法返回 r 值引用是否是一种好的做法?
- 在 C++ 中更改越界指针的取消引用是否安全?
- 本地引用是否由"DetachCurrentThread"清除?
- 从函数返回引用是否会导致在使用'auto'时创建新的临时对象?
- 常量右值引用是否允许对编译器进行额外优化?
- 如果参数传递两次,会发生什么情况?一次按值,一次按引用?是否会修改
- 返回强制引用是否安全