Re: const&
От: watchmaker  
Дата: 10.10.25 09:32
Оценка: 136 (8) +1
Здравствуйте, Videoman, Вы писали:

V>Опять что-то перемудрили в стандарте или я неправильно понимаю ссылочные квалификаторы у методов класса?


Проблема связана с общими правилами продления жизни временных объектов константными ссылками. А не с квалификаторами методов класса, как с очень частным случаем этого правила.


V> В сухом остатке вот выжимка.


Всё ещё слишком много лишнего :)

Более минимизированный пример c падением во время работы: https://godbolt.org/z/e1EnbbhvK
int main() {
    const int& bad = std::min(5, 6);
    printf("%d\n", bad); // UB
}


V> Стандарт позволяет вызвать метод у временного константного объекта.


И не только у метода — это опять же слишком частный случай.
Всегда и везде можно передавать временный объект по константной ссылке. Иначе бы такой код просто бы не компилировался:
const int good = std::min(5, 6);

Это дизайн языка, что по константной ссылке можно передать что угодно: число, строку или *this.

V>Понятно, что можно добавить метод
V>template<typename type_t>
V>nested_class get() const&& = delete;
V>
и всё будет работать как задумано.


Не нужно, пожалуйста, добавлять такие запрещения: от них вреда больше, чем пользы. Во-первых, они не все случаи ловят, во-вторых, они запрещают множество совершенно легитимных способов использовать классы:
printf("%d\n", holder_class().get<int>().get());

В твоём случае этот код не скомпилируется, хотя никакого UB нет.


Гораздо более практичный способ избежать подобных ошибок — использовать lifetimebound-атрибут, поддержка которого уже давно есть во многих компиляторах:
    
const nested_class& get() const& [[lifetimebound]];

После чего получать человекочитаемые сообщения:
error: temporary bound to local reference 'nested' will be destroyed at the end of the full-expression [-Werror,-Wdangling]
      |     const nested_class& nested = holder_class().get<int>(); 
      |                                  ^~~~~~~~~~~~~~

и при этом не получать ложных срабатываний при валидном использовании, в отличии от трюка с && = delete.

Демо: https://godbolt.org/z/ea6ovve7v
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.