#опытным
В нескольких предыдущих постах мы говорили про ref-qualified методы и как компилятор выбирает правильную перегрузку. Эта фича многим незнакома и сходу не очень понятно, где ее можно использовать. Давайте сегодня чуть подробнее поговорим о том, где они могут быть реально полезны, чтобы вы вдохновились и использовали такую перегрузку методов чаще.
✅ Разработка библиотек. Довольно очевидно, что разработчикам всяких библиотек нужно учитывать примерно все сценарии использования их классов. Пользователи(безумные) могут скастить объект к константной правой ссылке и методы класса должны работать корректно. Тут очень важно, чтобы тип возвращаемого значения методов соответствовал типу объекта. Пример:
template <typename T>
class optional {
constexpr T& value() & {
if (has_value()) {
return this->m_value;
}
throw bad_optional_access();
}
constexpr T const& value() const& {
if (has_value()) {
return this->m_value;
}
throw bad_optional_access();
}
constexpr T&& value() && {
if (has_value()) {
return std::move(this->m_value);
}
throw bad_optional_access();
}
constexpr T const&& value() const&& {
if (has_value()) {
return std::move(this->m_value);
}
throw bad_optional_access();
}
// ...
};
Если объект временный, то возвращаем правую ссылку на мувнутый ресурс. Если объект lvalue, то возвращаем обычную ссылку.
✅ Форсить ограничения на методы. Если у вас методы возвращают левые ссылки(константные и неконстантные), то неплохо бы их пометить
&, чтобы эти методы могли вызываться только у именованных объектов. Ведь если получить ссылку на внутренний ресурс временного объекта, то временный объект уничтожится, а вы останетесь с struct Vector {
int & operator[](size_t index) & { // notice & after arguments
return vec[index];
}
std::vector<int> vec;
};
Vector v;
v.vec = {1, 2, 3, 4};
v[1]; // ok
Vector{{1, 2, 3, 4}}[1]; // compile errorТакже прикрепляю ссылочку на быстрый ответ из блога стандарта С++ посвященный этому кейсу.
✅ Оптимизации. Иногда для определенных ссылочных типов мы можем оптимизировать какой-то метод. Например, в С++23 ввели rvalue reference перегрузку для метода substr класса std::basic_string. Мы знаем, что метод substr формирует новую строку, копируя туда рэндж из оригинальной строки. С++23 теперь сделал так, чтобы при вызове метода substr у правых ссылок объект подстроки тырил данные у оригинальной строки и фактически формировался из ее внутреннего буфера. Более подробно можно почитать в пропоузале.
Также, если вы возвращаете из метода легковесный объект, то в перегрузке для rvalue ссылок вы можете возвращать объект по значению. Так вы избавляетесь от избыточной ссылочной семантики и индирекции и , возможно, улучшаете перформанс. Ведь маленькие типы быстрее передавать и возвращать именно по значению:
struct Vector {
int operator[](size_t index) && { // notice & after arguments
return vec[index];
}
std::vector<int> vec;
};В общем, в каждом конкретном случае оптимизировать можно по-разному.
Так что ref-qualified методы - это прекрасный инструмент тонкой настройки в руках профессионалов.
Be useful. Stay cool.
#cppcore #optimization #cpp23