Могут ли ссылки на rvalue передаваться как ссылки на const? - PullRequest
0 голосов
/ 08 октября 2019

Рассмотрим следующий пример struct:

struct A {
    int i;

    void init(const A &a)
    {
        this->i = a.i;
    }

    A(int i)
    {
        this->i = i;
    }

    A(const A &a) = delete;
    A &operator=(const A &a) = delete;

    A(A &&a)
    {
        init(a); // Is this allowed?
    }

    A &operator=(A &&a)
    {
        init(a); // Is this allowed?
        return *this;
    }
};

Ссылка rvalue A &&a передается функции, принимающей const A &a, то есть постоянную ссылку lvalue. Это разрешено и приводит к хорошо определенному поведению в C ++?

Ответы [ 2 ]

1 голос
/ 08 октября 2019

Вам нужно привести a к rvalue в вашем примере, чтобы получить ожидаемый эффект, потому что сами имена переменных являются lvalues ​​(это сложная деталь lvalue и rvalues ​​в C ++). Итак, как написано, это правильно C ++, но не делает то, что, как вы думаете, делает.

Если вы приведете его, используя std::move(a) вместо a, код теперь делает то, что выхочу и все еще правильно. Это связано с тем, что в C ++ существует специальное правило, согласно которому временные привязки могут быть связаны с const lvalues ​​, более подробное обсуждение которых можно найти здесь . Эта функция очень удобна, когда у вас есть такой код:

void ProcessData(const std::vector<int>& input_vector);

, а затем вы хотите проверить его следующим образом:

ProcessData(std::vector<int>{1, 2, 3, 4, 5});

Это избавляет вас от необходимости явно создаватьобъект перед передачей в качестве const lvalue ссылки. Обратите внимание, что const здесь важен, без него код неверен. Существует более подробное обсуждение этого обоснования здесь .

1 голос
/ 08 октября 2019

Да, это разрешено.

Обратите внимание, что категория значений выражения a является lvalue, даже если объявленный тип a является ссылкой на rvalue.

Кроме того,если вы создаете rvalue из a с помощью std::move, ваш код по-прежнему правильно сформирован, поскольку rvalue может быть привязано к ссылке на постоянное значение:

init(std::move(a)); // std::move(a) is an rvalue (to be precise, xvalue), but still OK
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...