gpt4 book ai didi

c++ - 返回对绑定(bind)到临时的引用参数的引用时的悬空引用

转载 作者:行者123 更新时间:2023-12-04 17:15:57 25 4
gpt4 key购买 nike

这个问题引用Howard Hinnant 对问题Guaranteed elision and chained function calls 的回答。 .

在他的回答的底部,他说:

Note that in this latest design, if your client ever does this:

X&& x = a + b + c;

then x is a dangling reference (which is why std::string does not do this).

cppreference.com 上“引用初始化”一文的“临时生命周期”段落列出绑定(bind)到引用的临时对象的生命周期规则的异常(exception)情况。一个是:

"a temporary bound to a reference parameter in a function call exists until the end of the full expression containing that function call: if the function returns a reference, which outlives the full expression, it becomes a dangling reference."

我认为它的意思是“如果函数返回一个引用到引用参数绑定(bind)到的临时对象”,而不仅仅是一些其他引用。因此,我认为这就是解释 Howard Hinnant 上述陈述的规则。

以下示例基于我所指的问题中给出的示例:

struct X
{
int _x;
X() : _x(0) {}
X(int x) : _x(x) {}
X(X const& other) : _x(other._x) {}
X(X&& other) noexcept : _x(other._x) { other._x = 0; std::cout << "Move from " << &other << " to " << this << std::endl; }
X& operator+=(const X& other) { _x += other._x; return *this; }

friend X operator+(X const& lhs, X const& rhs)
{
std::cout << "X const& lhs: " << &lhs << std::endl;
X temp = lhs;
temp += rhs;
return temp;
}

friend X&& operator+(X&& lhs, X const& rhs)
{
std::cout << "X&& lhs: " << &lhs << std::endl;
lhs += rhs;
return std::move(lhs);
}
};

int anotherFunc(int a)
{
int bigArray[3000]{};
std::cout << "ignore:" << &bigArray << std::endl;
int b = a * a;
std::cout << "int b: " << &b << std::endl;
return 2 * b;
}

int main()
{
X a(1), b(2), c(3), d(4);
X&& sum = a + b + c + d;
std::cout << "X&& sum: " << &sum << std::endl;
anotherFunc(15);
std::cout << "sum._x: " << sum._x << std::endl;

return 0;
}

这打印

X const& lhs: 000000907DAFF8B4
Move from 000000907DAFF794 to 000000907DAFFA14
X&& lhs: 000000907DAFFA14
X&& lhs: 000000907DAFFA14
X&& sum: 000000907DAFFA14
ignore:000000907DAFC360
int b: 000000907DAFF254
sum._x: 10

当使用 MSVC 编译时;以及使用 gcc 或 clang 编译时的类似输出。

sum 应该是这里的悬空引用。尽管如此,仍会打印出正确的值“10”。它甚至可以在 sum 的引用初始化和通过所述引用进行访问之间将大型数组插入堆栈时起作用。用于 sum 引用的临时对象的内存不会被重用,并且总是在别处分配(相对于后续函数调用的堆栈帧),无论下一个堆栈帧有多大或多小。

为什么我测试过的每个编译器都保留 X&& operator+(X&& lhs, X const& rhs) 的本地临时对象,即使 sum 应该是悬空引用根据 cppreference.com 上的规则.或者,更准确地说:尽管访问悬空引用是未定义的行为,但为什么每个编译器都以这种方式实现它?

最佳答案

我喜欢为这种情况保留一个示例 class AA 的完整定义有点太长,无法在此处列出,但完整包含了它 at this link .

简而言之,A保存了一个state和一个statusstatus可以是其中之一这些枚举:

    destructed             = -4,
self_move_assigned = -3,
move_assigned_from = -2,
move_constructed_from = -1,
constructed_specified = 0

即特殊成员相应地设置状态。例如 ~A() 看起来像这样:

~A()
{
assert(is_valid());
--count;
state_ = randomize();
status_ = destructed;
}

还有一个流式运算符可以打印出这个类。

语言律师免责声明:打印出一个被破坏的 A 是未定义的行为,任何事情都有可能发生。话虽这么说,当编译实验时关闭优化,您通常会得到预期的结果。

对我来说,在 -O0 处使用 clang,这:

#include "A.h"
#include <iostream>

int
main()
{
A a{1};
A b{2};
A c{3};
A&& x = a + b + c;
std::cout << x << '\n';
}

输出:

destructed: -1002199219

将行更改为:

    A x = a + b + c;

结果:

6

关于c++ - 返回对绑定(bind)到临时的引用参数的引用时的悬空引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68711107/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com