【问题标题】:Can constexpr function return pointer of local object?constexpr 函数可以返回本地对象的指针吗?
【发布时间】:2018-05-22 12:06:22
【问题描述】:

constexpr 函数定义为 (c++14)

constexpr 函数必须满足以下要求:

  • 不能是虚拟的
  • 它的返回类型必须是 LiteralType 它的每个参数都必须是 LiteralType
  • 至少存在一组参数值,因此函数的调用可以是 核心常量表达式(对于构造函数,在常量中使用 初始化程序就足够了)(C++14 起)。无需诊断 违反此项目符号。

函数体必须被删除或默认或包含任何 语句除外:

  • asm 声明
  • goto 语句
  • 带有除 case 和 default 之外的标签的语句
  • 一个尝试块
  • 非文字类型变量的定义
  • 静态或线程存储持续时间变量的定义
  • 未对其执行初始化的变量的定义。

现在下面的func1满足要求并编译

constexpr int * func1 (int a)
{
  int b = 4;
  return &b;
}
int main()
{
    constexpr int * a = func1(3);
    int arr[*a];  
    std::cout << a << std::endl;
}

现在我的问题是 func1 怎么是 constexpr。它如何在编译时知道局部变量的地址?

我使用的是 gcc 6.4.0

【问题讨论】:

  • 我认为您在将第三个项目符号(“至少存在一组参数值......”)解释为满足时可能过于松懈。
  • 我的问题仍然有效。编译器如何在编译时知道局部变量的地址(与参数值无关)?
  • func1 不是 constexpr!
  • 你的问题只有在满足所有项目符号的前提下才有效。由于第三个可能不是,并且这种情况不需要诊断,因此答案是在最坏的情况下您会得到未定义的行为。
  • 请帮助理解这一点。第三个子弹说至少一组论点?无参数组合 make function constexpr.

标签: c++ c++14


【解决方案1】:

编译时如何知道局部变量的地址?

没有。

您的报价中的第三个项目符号永远不会满足:

至少存在一组参数值,使得 函数的调用可以是 a 的求值子表达式 核心常量表达式(对于构造函数,在常量中使用 初始化程序就足够了)(C++14 起)。 无需诊断 违反此项目符号。

编译器不会抱怨它,因为它不是必需的,直到你通过尝试在需要正确的 constexpr 函数的东西中使用 func1 来让它抱怨,例如:

std::array<int, func(3)> d;

这不会编译,你的编译器会告诉你原因。

【讨论】:

  • 好的。我认为编译器应该开始抱怨。我认为这是标准的缺陷
  • @code707 标准声明“不需要诊断”,所以你应该责怪标准,而不是编译器。
  • @SombreroChicken 在这种情况下,接受与否是实施质量问题。在更复杂的情况下,它可能是不可判定的。该标准对 NDR 是正确的
【解决方案2】:

现在我的问题是 func1 怎么是 constexpr。

你确定吗?

尝试询问编译时值,将其保存在constexpr 变量中;举例

constexpr int * a = func1(3);

您应该得到一个错误/警告列表,例如(来自我的 clang++ 3.8.1)

tmp_003-14,gcc,clang.cpp:7:11: warning: address of stack memory associated with
      local variable 'b' returned [-Wreturn-stack-address]
  return &b;
          ^
tmp_003-14,gcc,clang.cpp:11:21: error: constexpr variable 'a' must be
      initialized by a constant expression
    constexpr int * a = func1(3);
                    ^   ~~~~~~~~
tmp_003-14,gcc,clang.cpp:11:21: note: pointer to 'b' is not a constant
      expression
tmp_003-14,gcc,clang.cpp:6:7: note: declared here
  int b = 4;
      ^

实际上,从我的 g++ 6.3.0 中,我只收到一个警告

tmp_003-14,gcc,clang.cpp: In function ‘constexpr int* func1(int)’:
tmp_003-14,gcc,clang.cpp:7:7: warning: address of local variable ‘b’ returned [-Wreturn-local-addr]
   int b = 4;
       ^

【讨论】:

  • 我用g++ 6.4.0编译,编译输出0。
  • gcc 8.1.0 return 0(带有警告:返回局部变量'b'的地址)
  • @code707 - 有趣;我想重点是“违反此项目符号不需要诊断”;所以代码是错误的,但编译器不需要说出来。
  • @code707 哎呀。事实上,GCC 接受了这一点,即使在其当前的 8.1 版本中也是如此。我认为它将局部变量的返回转换为警告+空指针的返回(因为在函数返回后无论如何都不能使用局部变量),然后处理该空指针作为常数。
  • @max66 你用的是什么编译器?
【解决方案3】:

在您的代码中,当 func1() 返回时,b 将超出范围。
因此,在 func1() 之外与 b 相关的任何用法都是未定义的行为。 p>

constexpr int * func1 (int a)
{
  int b = 4; // remember: b is non-static
  return &b;
}

int * a = func1(3); // b is out of scope here

另外,来自expr.const

一个核心常量表达式满足:

(5.2) 如果值是指针类型,它包含一个地址 static 存储持续时间的对象,地址超过末尾 这样一个对象,一个函数的地址,或者一个空指针值

在您的情况下,b 不是 static,这意味着 func1() 不是 常量表达式

【讨论】:

  • 是的,这是模棱两可的。谁是正确的 g++ 或 clang ?是否需要更改标准以更清晰?
猜你喜欢
  • 2018-03-09
  • 1970-01-01
  • 1970-01-01
  • 2021-07-14
  • 2020-12-11
  • 2018-09-13
  • 2016-11-19
  • 1970-01-01
  • 2021-10-17
相关资源
最近更新 更多