三元运算符在return语句中给出了意外结果

时间:2018-10-01 16:46:33

标签: c++ reference return ternary-operator

我从三元运算符中获得了非常奇怪的结果,该运算符应该返回对链表的成员对象的引用。我的数据库对象中有如下成员函数:

DB::table("users")->insert([
  "password" => $request->input("password"), // or $request["password"]
  ...
]);

我在代码中两次调用了此函数:在加载数据库以获取信息之后,以及在更改月份的某些参数并按下按钮时。

我第一次将其写入const引用,这里没什么大不了的。但是第二次我需要非常量引用来重新计算月份(因此它也会在数据库中更改)。

但是发生了一些不可思议的事情,而不是预期的结果。每次调用Month& GetLastMonth() { return months_.Size() > 0 ? months_.Last() : Month(); } 函数时,它都会返回一个具有不同地址的引用。因此,在DB加载后-它的1个地址,重新计算月份-它的第二个地址,并保存到文件的第三个地址之后。当然,因此,重新计算月份后的更改不会保存到文件中。

现在,GetLastMonth()的大小始终为1(出于测试目的)。它也是链表,因此Month永远都无法重新分配。我已经对其进行了测试,并且它从未调用过months_,所以似乎三元运算符工作正常。

这样调用,会得到相同的结果:

Month()

但是,如果我不使用三进制调用它的话:

Month& GetLastMonth() { return months_.Size() ? months_.Last() : Month(); }

或使用适当的Month& GetLastMonth() { return months_.Last(); }

if()

它按预期方式工作,并且全部3次返回具有相同地址的引用。我已经花了大约两天的时间来思考这个晦涩的事情,但仍然找不到背后的任何理由。

编辑: 相关问题:Return type of '?:' (ternary conditional operator)

1 个答案:

答案 0 :(得分:3)

三元运算符会找到两个操作数的通用类型值类别,而在其他两种情况下不会发生这种情况,这就是为什么它在这里起作用的原因。

months_.Last()Month()都具有类型Month,所以一切都很好。但是现在,让我们检查值类别。 months_.Last()是左值,而Month()是prvalue!因此,此处的公用值类别是prvalue,并且两个操作数都转换为prvalue。这意味着您每次(从副本中)都从Month获得一个新的months_.Last()

但是请再次注意,这是MS特定的扩展名。如果没有该扩展名,则代码将无效,因为您将尝试将条件运算符返回的prvalue绑定到非const左值引用。