Зачем уничтожать std :: move из std :: shared_ptr - PullRequest
0 голосов
/ 04 мая 2020

Я получил некоторый код, похожий на этот

struct A
{
    int i;
    A(int i) : i(i) {}
    ~A()
    {
        cout << "destroy " << i << endl;
    }
};
using p = shared_ptr<A>;
p f(int i)
{
    return make_shared<A>(i);
}
int main()
{
    auto i = f(1);
    cout << "a" << endl;
    p && j = f(2);
    cout << "a" << endl;
    p && k = move(f(3));
    cout << "a" << endl;
    auto l = move(f(4));
    cout << "a" << endl;
    p ptr = make_shared<A>(5);
    auto && a = move(ptr);
    cout << "a" << endl;
}

, и на выходе получилось

a
a
destroy 3
a
a
a
destroy 5
destroy 4
destroy 2
destroy 1

Я не понимаю, почему move значение, возвращаемое функцией для ссылки на rvalue, вызывает разрушение. Но поместите его непосредственно в rvalue-ссылку, это нормально.

Проблема на самом деле обнаружена с std::get<> из std::tuple. У меня есть функция, которая возвращает кортеж из двух shared_ptr и использует std :: get <> для доступа к элементу. Но я обнаружил, что auto && i = get<0>(f()) вызовет ошибку, а auto i = get<0>(f()) - нет. Затем я нахожу похожую, но более простую ситуацию для std :: move

Ответы [ 3 ]

2 голосов
/ 04 мая 2020

Давайте go через эти по одному:

auto i = f(1); // (1)

Это создает локальную переменную i (не ссылку), инициализированную с возвращаемым значением f(1). Хорошо. Время жизни i до конца блока.

p && j = f(2); // (2)

Инициализирует ссылку j ссылкой на объект, возвращаемый f(2), и это продлевает время жизни значения возвращается f(2), так что все в порядке. Время жизни j до конца блока.

p && k = move(f(3)); // (3)

Инициализирует ссылку со ссылкой на объект, возвращаемый move, продление срока действия не происходит, поскольку значение, возвращаемое move является ссылкой на временное значение, возвращаемое f(2) (а не временным объектом), но временное значение, возвращаемое f(2), умирает, как только k инициализируется, так как его время жизни не увеличивается (это не присваивается ссылочной переменной), и k оказывается висячей ссылкой.

auto l = move(f(4)); // (4)

То же, что (1), движение бесполезно. Время жизни l до конца блока.

p ptr = make_shared<A>(5); // (5)

Это инициализация локальной переменной. Время жизни ptr - до конца блока.

auto && a = move(ptr);

a является ссылкой на ptr. Это не меняет время жизни ptr.

2 голосов
/ 04 мая 2020
p && j = f(2);

Здесь f возвращает значение типа std::shared_ptr<A>. Когда вы привязываете ссылку к prvalue, она продлевает время жизни prvalue до срока действия ссылки. Это означает, что объект, возвращаемый f, будет иметь то же время жизни, что и j.

p && k = move(f(3));

Здесь еще раз f возвращает значение prvalue. Параметр std::move связывается с этим значением, расширяя его время жизни до времени жизни параметра . std::move не возвращает значение prvalue. Возвращает значение x. Расширение времени жизни не применяется к значениям xvalue, поэтому объект, возвращаемый f, уничтожается, как только заканчивается время жизни параметра std::move. То есть он уничтожается, когда std::move возвращается. k становится привязкой.

1 голос
/ 04 мая 2020

Потому что с помощью std::move вы превратили возвращаемое значение в ссылку. И не постоянная ссылка, так что это временно.

Таким образом, копирование не выполняется, и как только строка заканчивается, возвращаемое значение уничтожается.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...