c++ - 为什么 lambda nullptr 取消引用在这种情况下有效?

标签 c++

我在运行代码时看到过类似的模式并自行尝试过,一切正常。这里特别有趣的一点是,我希望 (*(T*) nullptr) () 在运行时失败,但事实并非如此。这里是否有未定义的行为以及它为什么起作用?

template<typename T>
inline static int var = (*(T*) nullptr) ();

template<typename T>
int getvar (const T&)
{
    return var<T>;
}

int main ()
{
    int x = getvar ([]() { return 5; });
    return 0;
}

谢谢!

最佳答案

是的,这个程序有未定义的行为。 lambda 表达式的结果是未命名类类型的右值 [expr.prim.lambda.closure]/1有一个重载的函数调用运算符 [expr.prim.lambda.closure]/3 .因此,您在此处的示例中实质上正在做的事情

(*(T*) nullptr) ()

您是否正在对一个不存在的对象调用 lambda 类型的 operator ()(这是一个非静态成员函数)。您可以在此处找到有关为什么这是 UB 的更多详细信息:When does invoking a member function on a null instance result in undefined behavior?

虽然您肯定正在调用未定义的行为,但这种未定义的行为几乎肯定不会在您的特定示例中出现崩溃。原因很简单:lambda 的主体不访问类的任何成员,所以即使 operator () 是用 nullptr 调用的 this,它永远不会尝试访问基于该指针的任何内存。 lambda 的类型甚至没有任何成员,因为您的 lambda 不捕获任何内容。此外,在优化构建中,人们会期望编译器简单地从这个示例程序中优化掉 x,因为它没有任何可观察到的行为......

如果您将 var 模板设为 constexpr,编译器将拒绝编译它,因为用于初始化变量的表达式不是常量表达式,因为它会调用未定义的行为[expr.const]/2.6 ……

如果我们稍微修改一下您的示例,使 lambda 有一个成员,然后我们在 lambda 主体中访问该成员

template<typename T>
int getvar (const T&)
{
    return (*(T*) nullptr) ();
}

int main ()
{
    return getvar ([x = 42]() { return x; });
}

你很可能会得到一个实际上崩溃的程序......

关于c++ - 为什么 lambda nullptr 取消引用在这种情况下有效?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59338408/

相关文章:

c++ - 如何在不激活的情况下将其他应用程序窗口置于最前面?

c++ - '->C' 的左侧必须指向类/结构/union/通用类型

c++ - ibm i 7.3 上初始化 constexpr 编译时数组时出错

c++ - 以闪电般的速度缩放一组值

c++ - .访问违规读取位置

c++ - 无效输入后陷入循环

c++ - 使用 DirectXMath 中的 XMVECTOR 作为类成员会导致仅在 Release模式下崩溃?

C++ : Incorrect File Size Calculation WinAPI

c++ - 限制字段​​突变/访问命名空间

c++ - 将指向成员函数的指针作为 void* 函数的参数传递