Комментарии 11
Хорошо написанная хорошая статья. Спасибо. Отдельное уважение за продление жизни массива через ссылку на элементы.
Я считаю, что временные значения должный существовать только в рамках одного контекста. Если требуется вывести временное значение из-под этого контекста, значит надо пересмотреть архитектуру ПО.
Про код:
int id = 0;
int&& a = int[2]{1, 2}[id];
идея как-бы понятна.
Только кусок кода не компилируется (например, с применением вашего любимого https://cppinsights.io/). Возможно, лучше привести компилируемый кусок кода: всегда интересно посмотреть, как компилятор изворачивается.
Или: не туда смотрел, не так вставил. Может ссылочку на код в godbolt, cppinsights.io ?
Спасибо, что помогаете улучшить статью! Действительно, чтобы пример заработал придётся создавать массив немного хитрее (cppinsights):
template<typename T>
using dummy = T;
int main()
{
int i = 1;
auto&& a = dummy<int[3]>{1, 2, 3}[i];
}
Рекомендация не использовать такой трюк из п. 3.9 в таком свете становится ещё более актуальной.
Думаю, есть несколько проблем в реализации класса X с шаблонным конструктором.
По-видимому, считается, что такой конструктор заменяет конструктор по умолчанию. Нет, см. напр. в Vandevoorde - C++ Templates. То есть может использоваться move-конструктор по умолчанию, напр. если не гарантировано создание объекта in-place (как в C++17). https://cppinsights.io/s/997cc3fb
Я очень подозреваю UB с dangling reference в специализации X::X<int>(int &&)
, потому что в списке инициализации X(int &&l) : val(l) член класса val (lvalue ссылка) ссылается на локальную переменную l. Когда собирал с -O0, то получал val != 0. В случае с -O(>0) val == 0 на разных компиляторах в compiler explorer. Кажется странным, что там же pvs studio ругается на https://godbolt.org/z/Esc813ssd и не ругается на https://godbolt.org/z/rvjaezbbT, хотя результат зависит от оптимизации.
Спасибо за обратную связь!
Я очень подозреваю UB с dangling reference в специализации
X::X<int>(int &&)
, потому что в списке инициализацииX(int &&l) : val(l)
член классаval
(lvalue ссылка) ссылается на локальную переменнуюl
У меня тоже есть подобные подозрения, но полагаю, что точно выяснить как должно работать не получится. Потому что:
Теоретические методы завязаны анализе и синтезе стандарта и расплывчатой формулировки, от которой зависит истинность:
the initializer expression is used to initialize the destination object
Эмпирический подход даёт разные результаты на разных компиляторах (+ вариациях оптимизаций), на основе которых сложно делать однозначные выводы.
Да и выяснять это, судя по всему, имеет смысл только в рамках теоретических изысканий, поскольку на практике этот механизм ведёт себя слишком нестабильно на разных компиляторах, чтобы его использовать.
Поэтому я рекомендую интерпретировать такой код (и его вариации), как ведущий в висячим ссылкам и UB, и выпиливать его при встрече.
Продление жизни временных значений в С++: рецепты и подводные камни