Может ли функция constexpr вернуть указатель на локальный объект? - PullRequest
0 голосов
/ 22 мая 2018

Функция constexpr определяется как (c ++ 14)

Функция constexpr должна удовлетворять следующим требованиям:

  • она не должна быть виртуальной
  • его тип возвращаемого значения должен быть LiteralType, каждый из его параметров должен быть LiteralType
  • существует хотя бы один набор значений аргумента, так что вызов функции может быть оцененным подвыражением выражения основной константы (дляконструкторы, использование в константе инициализатора достаточно) (начиная с C ++ 14).Диагностика нарушения этого маркера не требуется.

тело функции должно быть либо удалено, либо задано по умолчанию, либо содержать любые операторы, кроме:

  • объявление asm
  • оператор goto
  • оператор с меткой, отличной от case и default
  • блок try
  • определение переменной не буквального типа
  • определение переменной статической или длительности хранения потока
  • определение переменной, для которой не выполняется инициализация.

Теперь следующий 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

Ответы [ 3 ]

0 голосов
/ 22 мая 2018

Как узнать адрес локальной переменной во время компиляции?

Нет.

Третий пункт в вашей цитате никогда не выполняется:

Существует, по крайней мере, один набор значений аргумента, так что вызов функции может быть оцененным подвыражением выражения основной константы (для конструкторов достаточно использования в инициализаторе константы) (поскольку C ++14). Диагностика нарушения этого маркера не требуется.

Компилятор просто не жалуется на это, потому что это не требуется, пока вы не заставите его жаловаться, пытаясь использоватьfunc1 внутри чего-то, что требует правильной constexpr функции, например:

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

Это не скомпилируется, и ваш компилятор скажет вам, почему.

0 голосов
/ 22 мая 2018

В вашем коде, когда возвращается func1(), b выходит за рамки.
Таким образом, любое использование, относящееся к b за пределами func1(), является неопределенным поведением .

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() это не a константное выражение .

0 голосов
/ 22 мая 2018

Теперь мой вопрос: почему 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;
       ^
...