Сообщение Re[4]: MSVC: A non-const reference may only be bound to an l от 26.07.2023 12:53
Изменено 26.07.2023 12:54 Sm0ke
Re[4]: MSVC: A non-const reference may only be bound to an lvalue
Здравствуйте, so5team, Вы писали:
S>В случае же когда параметр передается по ссылке, мы просто возвращаем эту же самую ссылку и на нее действуют обычные правила жизни.
S>Когда мы имеем дело с rvalue reference, то rvalue reference должно оставаться валидным в течении жизни выражения, в котором эта ссылка появилась. Т.е.:
S>
S>сперва у нас создается временный объект T и rvalue reference на него передается в первый вызов operator<<. Он эту же самую ссылку возвращает. И эта ссылка остается валидной, т.к. выражение у нас не завершилось. Когда вызывается второй operator<<, то эта ссылка отдается туда же. И там она опять же валидна, т.к. выражение все еще не завершилось.
Вы ошибаетесь. Рассмотрим пример:
Результат:
Время жизни временного объекта продлевается при привязке его на rvalue reference локальной переменной (или параметра) и откладывается до момента, когда переменная выйдет из scope. В данном случае время жизни параметра заканчивается после выхода из функции.
Иначе пример выше выдал бы сперва "going to return" из main(), а потом "~obj_t".
Тобишь когда выражение { obj_t && tmp = some_fn( obj_t{} ); } отработает, то tmp будет dangling ref.
При бинде одной rvalue ref от другой rvalue ref время жизни временного объекта дальше не продлевается. Только при бинде от самого временного объекта.
Корректный пример:
Результат:
К сожалению объект класса obj_t тут будет создан дважды.
Сперва default constructor, потом move constructor, потом дважды destructor.
В случае вектора — мув конструктор считается относительно дешёвым.
S>В случае же когда параметр передается по ссылке, мы просто возвращаем эту же самую ссылку и на нее действуют обычные правила жизни.
S>Когда мы имеем дело с rvalue reference, то rvalue reference должно оставаться валидным в течении жизни выражения, в котором эта ссылка появилась. Т.е.:
S>
S>T && operator<<(T && d, int v) { ...; return std::move(d); }
S>(T{} << 0) << 1;
S>S>сперва у нас создается временный объект T и rvalue reference на него передается в первый вызов operator<<. Он эту же самую ссылку возвращает. И эта ссылка остается валидной, т.к. выражение у нас не завершилось. Когда вызывается второй operator<<, то эта ссылка отдается туда же. И там она опять же валидна, т.к. выражение все еще не завершилось.
Вы ошибаетесь. Рассмотрим пример:
#include <utility>
#include <iostream>
struct obj_t {
bool f = false;
obj_t() { std::cout << "obj_t default\n"; }
~obj_t() { std::cout << "~obj_t\n"; }
obj_t(obj_t &&) { std::cout << "obj_t move\n"; }
obj_t(const obj_t &) { std::cout << "obj_t copy\n"; }
};
obj_t && some_fn(obj_t && o) { return std::move(o); } // bad
int main() {
obj_t && tmp = some_fn( obj_t{} ); // tmp битая ссылка
std::cout << "going to return\n";
return 0;
}Результат:
obj_t default
~obj_t
going to returnВремя жизни временного объекта продлевается при привязке его на rvalue reference локальной переменной (или параметра) и откладывается до момента, когда переменная выйдет из scope. В данном случае время жизни параметра заканчивается после выхода из функции.
Иначе пример выше выдал бы сперва "going to return" из main(), а потом "~obj_t".
Тобишь когда выражение { obj_t && tmp = some_fn( obj_t{} ); } отработает, то tmp будет dangling ref.
При бинде одной rvalue ref от другой rvalue ref время жизни временного объекта дальше не продлевается. Только при бинде от самого временного объекта.
Корректный пример:
#include <utility>
#include <iostream>
struct obj_t {
bool f = false;
obj_t() { std::cout << "obj_t default\n"; }
~obj_t() { std::cout << "~obj_t\n"; }
obj_t(obj_t &&) { std::cout << "obj_t move\n"; }
obj_t(const obj_t &) { std::cout << "obj_t copy\n"; }
};
obj_t some_fn(obj_t && o) { return std::move(o); } // good
int main() {
obj_t && tmp = some_fn( obj_t{} );
std::cout << "going to return\n";
return 0;
}Результат:
obj_t default
obj_t move
~obj_t
going to return
~obj_tК сожалению объект класса obj_t тут будет создан дважды.
Сперва default constructor, потом move constructor, потом дважды destructor.
В случае вектора — мув конструктор считается относительно дешёвым.
Re[4]: MSVC: A non-const reference may only be bound to an l
Здравствуйте, so5team, Вы писали:
S>В случае же когда параметр передается по ссылке, мы просто возвращаем эту же самую ссылку и на нее действуют обычные правила жизни.
S>Когда мы имеем дело с rvalue reference, то rvalue reference должно оставаться валидным в течении жизни выражения, в котором эта ссылка появилась. Т.е.:
S>
S>сперва у нас создается временный объект T и rvalue reference на него передается в первый вызов operator<<. Он эту же самую ссылку возвращает. И эта ссылка остается валидной, т.к. выражение у нас не завершилось. Когда вызывается второй operator<<, то эта ссылка отдается туда же. И там она опять же валидна, т.к. выражение все еще не завершилось.
Вы ошибаетесь. Рассмотрим пример:
Результат:
Время жизни временного объекта продлевается при привязке его на rvalue reference локальной переменной (или параметра) и откладывается до момента, когда переменная выйдет из scope. В данном случае время жизни параметра o заканчивается после выхода из функции some_fn() .
Иначе пример выше выдал бы сперва "going to return" из main(), а потом "~obj_t".
Тобишь когда выражение { obj_t && tmp = some_fn( obj_t{} ); } отработает, то tmp будет dangling ref.
При бинде одной rvalue ref от другой rvalue ref время жизни временного объекта дальше не продлевается. Только при бинде от самого временного объекта.
Корректный пример:
Результат:
К сожалению объект класса obj_t тут будет создан дважды.
Сперва default constructor, потом move constructor, потом дважды destructor.
В случае вектора — мув конструктор считается относительно дешёвым.
S>В случае же когда параметр передается по ссылке, мы просто возвращаем эту же самую ссылку и на нее действуют обычные правила жизни.
S>Когда мы имеем дело с rvalue reference, то rvalue reference должно оставаться валидным в течении жизни выражения, в котором эта ссылка появилась. Т.е.:
S>
S>T && operator<<(T && d, int v) { ...; return std::move(d); }
S>(T{} << 0) << 1;
S>S>сперва у нас создается временный объект T и rvalue reference на него передается в первый вызов operator<<. Он эту же самую ссылку возвращает. И эта ссылка остается валидной, т.к. выражение у нас не завершилось. Когда вызывается второй operator<<, то эта ссылка отдается туда же. И там она опять же валидна, т.к. выражение все еще не завершилось.
Вы ошибаетесь. Рассмотрим пример:
#include <utility>
#include <iostream>
struct obj_t {
bool f = false;
obj_t() { std::cout << "obj_t default\n"; }
~obj_t() { std::cout << "~obj_t\n"; }
obj_t(obj_t &&) { std::cout << "obj_t move\n"; }
obj_t(const obj_t &) { std::cout << "obj_t copy\n"; }
};
obj_t && some_fn(obj_t && o) { return std::move(o); } // bad
int main() {
obj_t && tmp = some_fn( obj_t{} ); // tmp битая ссылка
std::cout << "going to return\n";
return 0;
}Результат:
obj_t default
~obj_t
going to returnВремя жизни временного объекта продлевается при привязке его на rvalue reference локальной переменной (или параметра) и откладывается до момента, когда переменная выйдет из scope. В данном случае время жизни параметра o заканчивается после выхода из функции some_fn() .
Иначе пример выше выдал бы сперва "going to return" из main(), а потом "~obj_t".
Тобишь когда выражение { obj_t && tmp = some_fn( obj_t{} ); } отработает, то tmp будет dangling ref.
При бинде одной rvalue ref от другой rvalue ref время жизни временного объекта дальше не продлевается. Только при бинде от самого временного объекта.
Корректный пример:
#include <utility>
#include <iostream>
struct obj_t {
bool f = false;
obj_t() { std::cout << "obj_t default\n"; }
~obj_t() { std::cout << "~obj_t\n"; }
obj_t(obj_t &&) { std::cout << "obj_t move\n"; }
obj_t(const obj_t &) { std::cout << "obj_t copy\n"; }
};
obj_t some_fn(obj_t && o) { return std::move(o); } // good
int main() {
obj_t && tmp = some_fn( obj_t{} );
std::cout << "going to return\n";
return 0;
}Результат:
obj_t default
obj_t move
~obj_t
going to return
~obj_tК сожалению объект класса obj_t тут будет создан дважды.
Сперва default constructor, потом move constructor, потом дважды destructor.
В случае вектора — мув конструктор считается относительно дешёвым.