保持对局部变量的常量引用是 UB 吗?

Is it UB to keep a const-reference to a local variable?

提问人:Juliean 提问时间:11/5/2021 最后编辑:Juliean 更新时间:11/9/2021 访问量:179

问:

在编译启用代码优化(准确地说是 MSVC)时,我遇到了多个问题。实际情况是大型代码库的一部分,需要复杂的设置才能复制,但本质上可以归结为以下结构:

struct VariableView
{
    const void* pValue;
};

template<typename Type>
[[nodiscard]] VariableView createView(const Type& value)
{
    return {&value};
}

void serializeStruct(Struct value)
{
    const auto view = createView(value);

    serializeGeneric(view);
}

我遇到的错误围绕着“value”的内容在调用“createView”之后被覆盖,但在调用“serializeGeneric”之前/之前。这是我通过调试和查看生成的程序集所能知道的,所以我假设编译器以某种方式(错误地)假设变量“value”在调用 createView 后不再使用,因此决定将下一个必需的值重新分配给其原始本地值。

但是,在我向 MSVC 编译器提交错误报告之前,我想确保:由于标准,我在这里所做的实际上应该是有效的 C++,还是我通过将局部变量的地址存储在“VariableView”结构中来遇到 UB 我正在做的方式?

编辑:好的,所以我已经能够把问题归结为问题。编译器的混淆似乎来自这样一个事实,即实际代码中的类型是由模板推导出来的。这是重现该问题的完整代码:

https://www.paste.org/120337(对不起,编辑一直说我的代码格式不正确,所以我不得不使用外部网站)。

在带有 /O2 的 MSVC 中,accessData 中“临时”结构的前两个变量将损坏(O1 或更低可解决问题。按值传递string_view似乎是导致值被覆盖的原因。 如果我将参数列表中的类型特征替换为它们的简单定义,即使该特征解析为完全相同的基础类型,该错误实际上也会消失。所以,如果你认为这里还有其他可疑的东西,请告诉我,但我也会提交一份错误报告,因为我现在非常确定它是不对的(而且我现在有一个最小的例子)。

编辑2:我的报告已提交(https://developercommunity.visualstudio.com/t/Type-trait-as-argument-type-leads-to-opt/1572875)并且已经在调查中。

C++ 按引用传递 标准 未定义的行为

评论

6赞 François Andrieux 11/5/2021
更有可能的是,代码中的其他位置存在导致该问题的问题,而不是编译器错误。至少,您需要为此类问题提供一个最小的可重现示例。UB 的结果通常可以在远离其原因的地方观察到,问题的原因不必在您看到问题的地方附近。
2赞 François Andrieux 11/5/2021
回答被问到的问题:在这种情况下,它的寿命是独立的,并且它总是会比它活得更久。代码没有任何明显的错误。valueview.pValue
0赞 alagner 11/5/2021
你不是,在序列化之前,一切似乎都是有效的 C++;请注意,如果 serializeGeneric 包含 UB,编译器无论如何都可以自由地执行任何操作,因此我会将其替换为 no-op 函数调用并查看它是否重复(前提是此示例能够重现该错误)。
0赞 Juliean 11/5/2021
@FrançoisAndrieux:如果编译器看不到 VariableView 的 constexpr,这是否同样适用于生存期?这就是实践中发生的事情,这也是 serializeGeneric 所发生的事情。我会尝试获得一个样本来重现,但我相信它完全符合我的描述。虽然我还不能单独重现,但我能够将导致错误的代码段提取到一个空项目中,之前或之后没有调用其他代码,所以除了这段代码之外,不应该有任何 UB。
0赞 François Andrieux 11/5/2021
pastebin 代码是不同的。你取一个地址,它是一个函数本地对象,函数返回一个悬空的指针。当您取消引用它时,这会导致 UB in。在问题中提供的代码中有一个参考。valueAccessDatavalue

答: 暂无答案