Const ссылка на временный объект не продлевает срок его службы - PullRequest
0 голосов
/ 04 ноября 2019

У меня есть класс, из которого я создаю временный объект. Я могу привязать const-ссылку к этому временному объекту, и он работает как положено. Однако, если я вызываю функцию-член, которая возвращает std :: move (* this), для этого временного объекта и связывается с этим возвращаемым значением, это не работает, как я ожидал. Краткий код ниже воспроизводит мою проблему и не требует пояснений.

#include <iostream>
#include <cstdlib>
#include <vector>

class myval {
    public:
    std::vector<int> i;
    myval(int i) : i({i}) {}
    myval(const myval& v) = delete;
    myval(myval&& v) : i(std::move(v.i)) {}
    myval&& addone() && {
        i[0]++;
        return std::move(*this);
    }

};

int main()
{
    //Object is moved, works like expected
    const auto moved_value = myval{7}.addone();
    std::cout << moved_value.i[0] << std::endl;

    //Const reference is supposed extend the lifetime of a temporary object
    const auto& u = myval{7};
    //Prints 7, as expected
    std::cout << u.i[0] << std::endl;

    const auto& v = myval{7}.addone();
    //Why does this print 0?
    std::cout << v.i[0] << std::endl;

    return 0;
}

Редактировать:

  1. Учитывая, что объяснение может быть для этого, можно ли сделатьэта работа так, что назначение "const auto& v = ...." работает?

  2. Почему следующее назначение работает, когда my не работает?

    const auto& s = std::string("hi")[1];
    std::cout << s;
    

Ответы [ 2 ]

5 голосов
/ 04 ноября 2019

Постоянная ссылка только продлевает время жизни функции локальных временных. В строке

const auto& v = myval{7}.addone();

ваша ссылка не является временной привязкой. addone возвращает по ссылке, что означает, что вы работаете с lvalue вместо временного, и, следовательно, когда закончится полное выражение, у вас останется ссылка на объект, который больше не существует.


Относительно правок,Чтобы сделать

const auto& v = myval{7}.addone();

, я бы изменил addone так, чтобы он возвращался по значению наподобие

myval addone() && {
    i[0]++;
    return std::move(*this);
}

Это даст вам правильное поведение при перемещении объекта во временное состояние, которое вы затемпродлите время жизни.

Для

const auto& s = std::string("hi")[1];
std::cout << s;

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

1 голос
/ 04 ноября 2019

Увеличение срока действия ссылки работает только при непосредственном применении к лбу временному объекту.

При применении к ссылке расширение срока действия ссылки не существует.

myval&& addone() && {
    i[0]++;
    return std::move(*this);
}

возвращает ссылку. (ссылки на rvalue и lvalue являются видами ссылок)

const auto& v = myval{7}.addone();

это не делает продление срока действия ссылки, потому что мы привязываем const auto& v к ссылке, а не к временной.


Как мы можем заставить это работать? Что ж, переписав подпись addone, мы получим:

myval addone() && {
    i[0]++;
    return std::move(*this);
}

теперь она возвращает значение вместо ссылки.

const auto& v = myval{7}.addone();

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

Ваш ответ «почему это работает» связан с тем, что неопределенное поведение может делать все, в том числе «кажется, работает». Это неверный код.

...