UB в неоцененном контексте (например, требует-выражений) по-прежнему UB? - PullRequest
12 голосов
/ 25 мая 2020

C ++ 20 draft [concept.default.init] не определяет точно default_initializable

template<class T>
concept default_initializable = constructible_from<T> &&
    requires { T{}; } &&
    is-default-initializable <T>; // exposition-only

и описывает, что инициализируется по умолчанию следует использовать со следующими словами:

Для типа T, is-default-initializable истинно тогда и только тогда, когда определение переменной

T t;

хорошо сформировано для некоторой придуманной переменной t; в противном случае это ложь. Проверка доступа выполняется, как если бы в контексте, не связанном с T. Учитывается только действительность непосредственного контекста инициализации переменной.

На cppreference мы находим следующее предложение для возможная реализация:

template<class T>
concept default_initializable =
    std::constructible_from<T> &&
    requires { T{}; } &&
    requires { ::new (static_cast<void*>(nullptr)) T; };

Оператор размещения-new, вызываемый с аргументом nullptr, приводит к неопределенному поведению.

9) Вызывается новое выражение стандартного размещения одного объекта. Реализация стандартной библиотеки не выполняет никаких действий и возвращает ptr без изменений. Поведение не определено, если эта функция вызывается через выражение размещения new, а ptr является нулевым указателем.

У меня вопрос: действительно ли предложенная возможная реализация действительна? С одной стороны, я думаю, что нет, потому что задействовано выражение, которое демонстрирует неопределенное поведение. С другой стороны, я думаю, что да, потому что это выражение встречается в неоцененном контексте и, следовательно, может не иметь четко определенного поведения (?) И просто должно быть синтаксически правильным. Но я не могу найти четких доказательств того или другого.

Второй вопрос: если последнее окажется правдой, то почему эта новая конструкция размещения удовлетворяет стандартному требованию, что T t; должно быть хорошо- сформирован? Мне это кажется странным хаком, потому что ни простые, ни сложные требования не дают возможности требовать T t; точно. Но почему это работает?

1 Ответ

0 голосов
/ 24 июня 2020

Если указано, неопределенное поведение является следствием оценки [expr.new] / 20

Если функция распределения является формой без выделения ([new. delete.placement]), который возвращает значение null, поведение не определено.

[expr.prim.req] / 2 :

Отображаемые выражения в теле требования находятся неоцененные операнды.

[expr.prop] / 1 :

Неоцененный операнд не оценивается.

Таким образом, неопределенное поведение отсутствует, если требуется возвращаемое значение новой функции распределения размещения, но такое значение не вычисляется.

Если бы это было не так, такая общая конструкция decltype( std::declval<int&>() + std::declval <int&> ()) тоже будет UB.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...