Как стать автором
Обновить

Комментарии 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

У меня тоже есть подобные подозрения, но полагаю, что точно выяснить как должно работать не получится. Потому что:

  1. Теоретические методы завязаны анализе и синтезе стандарта и расплывчатой формулировки, от которой зависит истинность: the initializer expression is used to initialize the destination object

  2. Эмпирический подход даёт разные результаты на разных компиляторах (+ вариациях оптимизаций), на основе которых сложно делать однозначные выводы.

Да и выяснять это, судя по всему, имеет смысл только в рамках теоретических изысканий, поскольку на практике этот механизм ведёт себя слишком нестабильно на разных компиляторах, чтобы его использовать.

Поэтому я рекомендую интерпретировать такой код (и его вариации), как ведущий в висячим ссылкам и UB, и выпиливать его при встрече.

Подозрения по поводу UB больше нет, оно там есть, так как ссылка привязывается к переменной l локальной для конструктора. Та же проблема, что и при возврате ссылки из функции - данных нет, ссылка осталась.

По-видимому, считается, что такой конструктор заменяет конструктор по умолчанию

Можете, пожалуйста, уточнить какая формулировка из п. 3.7 натолкнула на такую мысль?

Ещё раз аккуратно перечитал. Это замечание - не проблема примера. В примере не используются copy/move-конструкторы X. Тогда пусть будет дополнением. Спасибо, что обратили внимание.

Спасибо вам за уточнения и проявленный к статье интерес!

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории