У меня была ошибка во время выполнения, когда заменили некоторый код с помощью 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;
}
Это незначительный недостаток дизайна, вызванный двумя конкурирующими потребностями.
Во-первых, избегая лишних ходов, а во-вторых, включив продление срока службы ссылки.
Эти два конкурируют в текущем C ++; Вы обычно не можете решить обе проблемы одновременно. Таким образом, вы увидите код, выполняющий одно или другое, совершенно случайно.
Я лично нахожу возвращение ссылки на rvalue, чтобы создать больше проблем, чем переход от объекта, который скоро будет уничтожен, но тех, кто стандартизировал std::optional
не согласился.
Мое предпочтительное решение будет иметь другие недостатки.
Чтобы это исправить — чтобы не приходилось идти на эти компромиссы — нам потребуется сложное грязное переопределение того, как работает продление срока службы. Таким образом, мы должны жить с этими проблемами сейчас.
возврате T
вынуждает двигаться, создает его, в то время как обратная ссылка (rvalue-) не требует затрат.
Предположим, что у вас есть
std::optional<std::array<T, N>> getOptional();
затем
getOptional().value()
будет делать несколько копий (RVO здесь не применяется, так как возвращает (перемещенный) член).