使用行为不同的引用返回TMP
returning tmp using references behaving differently
我知道使用引用返回临时变量不起作用,因为在函数终止后临时对象丢失了,但是下面的代码可以工作,因为返回的临时对象被赋值给了另一个对象。
我假设临时对象在函数调用行之后被销毁。如果是这样,为什么这种方法链不能工作呢?
Counter& Counter::doubler()
{
Counter tmp;
tmp.i = this->i * 2;
return tmp;
}
int main()
{
Counter d(2);
Counter d1, d2;
d1 = d.doubler(); // normal function call
std::cout << "d1=" << d1.get() << std::endl; // Output : d1=4
d2 = d.doubler().doubler(); // Method chaining
std::cout << "d2=" << d2.get() << std::endl; // Output : d2=0
return 0;
}
如果函数返回对局部对象的引用,则该对象将在函数返回时立即销毁(就像局部对象一样)。不持续到函数调用的行末。
在对象被销毁后访问它将产生不可预测的结果。对于"工作"的某些定义,有时它可能有效,有时则可能无效。别这么做
Counter& doubler()
{
Counter tmp;
tmp.i=this->i*2;
return tmp;
}
这是未定义的行为。从函数返回后,你的引用将是悬空的,因为Counter
析构函数将被局部对象tmp
调用。
真正的问题不是"为什么这种方法链不工作?",而是"为什么第一个('正常')函数调用工作?"
答案是没有办法知道,因为它可能会破坏你的程序。
说明清楚:通过引用返回临时对象是未定义的行为。当然,这意味着它可能今天碰巧起作用,明天就不起作用了。
当函数返回并发生堆栈回滚时,这是逻辑回滚,堆栈指针被设置为不同的值。如果函数返回一个局部变量引用,那么指向local的内存位置可能仍然在进程中,并且设置了相同的位。然而,这并不能保证,在几次调用之后将无效,并可能导致未定义的行为。
其他的都是可以的,只是"不要摆弄本地对象的引用"
至于为什么它在一种情况下起作用而在其他情况下不起作用
-
当你单独调用它时,当函数返回时,对象仍然在堆栈上。授予一个"销毁"的对象-但是无论该对象占用的空间如何,它仍然存在于堆栈中。如果你有一个简单的对象,比如只有一个int成员,那么它在堆栈上没有任何干扰,除非你在堆栈上分配了其他东西,或者析构函数决定做一个非常彻底的工作并删除一个整数成员(大多数析构函数都不会这样做)。当然啦,但是直到下一行之前都不会发生什么事情会把它从堆栈中移走。您的引用指向一个有效的内存位置,并且您的(销毁)对象将在那里。这就是为什么它对你有效。
-
当你链式调用它时,看到第一个调用返回一个对栈上tmp的引用。正如上面第1条所解释的,到目前为止没有问题。您的(已销毁的)tmp仍然在堆栈上。但请注意你调用第二个加倍器的时刻。第二个双倍器函数调用中的tmp在哪里?就在你第一次调用tmp的地方!!第二个调用用一个值为0的tmp(默认构造的tmp)覆盖对象(值为4的tmp)。第二个调用实际上是在一个值为0的Counter上进行的,因此您得到0。非常棘手——这就是为什么要忘记返回对局部变量的引用。
现在纯粹主义者可能会尖叫-没有定义,不,不,只是不要这样做-我和他们一样-我自己说过两次(现在是三次)不要这样做。但人们可能会尝试。我打赌像下面这样的"简单"对象,和问题中的代码完全一样(以便没有任何东西干扰堆栈),每个人都会得到一致的4,0 -没有随机性,没有未定义....
class Counter
{
public:
Counter()
{
i = 0;
}
Counter(int k)
{
i = k;
}
int get()
{
return i;
}
int i;
Counter& doubler();
};
- 如何通过引用返回对象
- 函数如何使用引用返回所需的数字?
- 如何防止引用返回的私有结构的突变
- 如何在不使用临时变量的情况下取消引用返回指针的函数的返回值?
- 通过引用返回的变量的范围
- 对于具有引用返回类型的搜索算法,默认返回值应该是什么?
- 运算符重载C++类中的引用返回
- C++对象引用返回不同的值
- 解释通过从函数引用返回数组的语法
- 具有引用返回类型的重写方法上的协变返回类型无效
- 为什么在通过引用返回运算符分配时取消引用'this'指针?
- 为什么我在函数中使用引用并通过引用返回它仍然有效?
- 直接在 C++ 中将值分配给引用返回类型
- C++当您取消引用指向类对象的指针,然后将其作为引用返回时,是否可以对此引用调用方法
- 可以通过常量引用返回默认参数的值吗?
- 按值与右值引用返回
- 非常量引用返回函数在常量值返回函数上用作 r 值
- 当我使用按引用返回时,我不知道这些代码之间的区别
- 为什么通过引用返回向量比通过移动返回要快得多?
- 通过引用返回包含对象的向量