Почему std::option::value() &&; вернуть &&?

У меня была ошибка во время выполнения, когда заменили некоторый код с помощью std:: option:

Старый код:

T getValue();
...
const auto& value = getValue();
value.get();

Новый код:

std::optional<T> getValue();
...
const auto& value = getValue().value();
value.get(); // Runtime error, crash 

Это было непредсказуемо для меня. Причина сбоя в том, что метод возвращает T&&,

Мой вопрос в каких случаях T&& может быть полезно, почему метод не возвращает T,

Полный код:

#include <experimental/optional>
#include <iostream>
#include <memory>

struct Value {
    std::unique_ptr<int> a = std::make_unique<int>(5);
};

std::experimental::optional<Value> getValue() {
    Value v;
    return v;
}

int main() {
    const Value& value = getValue().value();
    std::cout << *value.a << std::endl;
    return 0;
}

2 ответа

Решение

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

Во-первых, избегая лишних ходов, а во-вторых, включив продление срока службы ссылки.

Эти два конкурируют в текущем C++; Вы обычно не можете решить обе проблемы одновременно. Таким образом, вы увидите код, выполняющий одно или другое, совершенно случайно.

Я лично нахожу возвращение ссылки на rvalue, чтобы создать больше проблем, чем переход от объекта, который скоро будет уничтожен, но тех, кто стандартизировал std::optional не согласился.

Мое предпочтительное решение будет иметь другие недостатки.

Чтобы это исправить - чтобы не приходилось идти на эти компромиссы - нам потребуется сложное грязное переопределение того, как работает продление срока службы. Таким образом, мы должны жить с этими проблемами сейчас.

Возврате T вынуждает двигаться, создает его, в то время как обратная ссылка (rvalue-) не требует затрат.

Предположим, что у вас есть

std::optional<std::array<T, N>> getOptional();

затем

getOptional().value()

будет делать несколько копий (RVO здесь не применяется, так как возвращает (перемещенный) член).

Другие вопросы по тегам