Почему функции emplace () в c ++ 17 не переопределены? - PullRequest
0 голосов
/ 09 января 2019

C ++ 17 ввел новую сигнатуру функции для нескольких функций типа emplace_back() (тоже есть в std::optional<>), но они не имеют повторной квалификации. Это позволяет вызывать emplace_back() во временных и привязанных к lvalue ссылках, даже если время жизни объекта не увеличивается. Учтите следующее:

#include <vector>
#include <optional>
#include <iostream>

struct A {
   A(int i) : i(i) { std::cout << "constructor called: " << i << '\n'; }
   ~A() { std::cout << "destructor called\n"; }

   int i;
};

int main() {
    auto & a = std::optional<A>().emplace(5);
    std::cout << "a: " << a.i << '\n';
    auto & v = std::vector<A>().emplace_back(5);
    std::cout << "v: " << v.i << '\n';

    // This fails to compile, because value() *is*
    // ref-qualified so it cannot bind to an lvalue reference
    //auto & a2 = std::optional<A>(std::in_place, 5).value();

    auto const & a2 = std::optional<A>(std::in_place, 5).value();
    std::cout << "a2: " << a2.i << '\n';
}

Выход:

constructor called: 5
destructor called
a: 5
constructor called: 5
destructor called
v: 0
constructor called: 5
destructor called
a2: 5

Я не смог найти никаких существующих ошибок или вопросов, связанных с этим, но, возможно, я просто что-то упустил. В случае std::optional<>::value(), это , в основном , работает, но все же позволяет связывать константы с lvalue-ссылками, в то же время не продлевая должным образом время жизни содержимого типа.

Есть ли какая-либо причина, по которой эти функции не являются повторно квалифицированными, и почему std::optional<>::value() неправильно продлевает время жизни содержимого объекта при использовании в rvalue?

Ответы [ 2 ]

0 голосов
/ 09 января 2019

Есть ли какая-либо причина, по которой эти функции не переосмыслены, и [...]

В стандартной библиотеке есть много функций, которые могут быть & -квалифицированными, но не являются. Вызов emplace() -подобных методов для rvalue, вероятно, является хорошим примером кода, который, вероятно, не имеет большого смысла.

С другой стороны, вероятно, не так много людей пытаются вызвать emplace() -подобные методы для rvalues, так что, возможно, отдача от & -квалификации всех этих функций не стоит времени.

[...] и почему std::optional<>::value() неправильно продлевает время жизни содержимого объекта при использовании в rvalue?

Это не может продлить жизнь. Там нет такого языкового средства. Выбор заключается в том, чтобы либо вернуть значение (которое может вызвать перемещение, которое вам может не понадобиться, но будет безопасным), либо вернуть ссылку (которая позволяет избежать ненужных перемещений, но полагается на то, что программист использует ее безопасно). Библиотека выбрала последнее.

0 голосов
/ 09 января 2019

Почти ничего в библиотеке std не уточнено.

Что касается value, он возвращает ссылку на значение. Если у вас есть метод с квалификацией rvalue, возвращающий ссылку на внутреннее состояние, у вас есть два варианта.

Вы можете вернуть значение или вернуть ссылку на значение.

Если вы возвращаете значение, это означает, что .value() для необязательного значения rvalue выполняет перемещение, а .value() для необязательного значения lvalue - нет. Это может быть удивительно.

Стоимость .value() возврата rvalue заключается в том, что ссылочное продление срока службы не применяется. Стоимость .value() возврата копии по значению r - это стоимость перемещения плюс неожиданность того, что она ведет себя по-другому.

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

Если исключить экстремальное улучшение ссылочного продления времени жизни, функции для значений r, возвращающие значения во внутреннее состояние, всегда будут связываться с const& и не продлевают время жизни внешнего объекта.

Реальная болевая точка в моем опыте - for(:) петли;

std::optional<std::vector<int>> try_get_vec();

for (int x : try_get_vec().value()) // I know the optional won't be empty

Вышеуказанное имеет висячую ссылку.

...