Я хотел бы знать, если следующий код является действительным.
В частности, я озадачен временем жизни объектов, задействованных здесь, после вызова new_S.
Насколько я понимаю, T будет скопирован при обработке списка инициализаторов и, возможно, в конструкторе перемещения вектора.
А как насчет вектора RValue? это все еще действует после возвращения из new_S? Я бы сказал нет, но я точно не уверен
struct T
{
int t;
};
struct S
{
S(std::vector<T>&& s) : s_(std::forward<std::vector<T>>(s)) {}
std::vector<T> s_;
};
S* new_S()
{
return new S{{{1}, {2}, {3}}};
}
После возвращения из new_S
нет вектора RValue (я предполагаю, что вы имеете в виду параметр ссылки rvalue для конструктора). Ссылка на значение существует только во время построения S.
Несколько слов к вашему коду: std::forward
это работа здесь. Это нужно только для идеальной пересылки универсальных ссылок, и std::vector<T>
не универсальный реф, а ревал (посмотреть здесь). использование std::move
в этом случае.
Сказав это, вы не должны проходить мимо rvalue-ref в своем конструкторе. Вместо этого передайте по значению:
struct S
{
S(std::vector<T> s) : s_{std::move(s)} {}
std::vector<T> s_;
};
Таким образом, у вас будет лучшее решение для любого пройденного значения, посмотреть здесь:
s
строится на основе аргумента, после этого s_
построено из s
, Копии не сделаны.s
после этого создается копия, s_
построено из s
, Сделана только одна необходимая копия.Последнее, но не менее важное: не используйте сырые указатели и new
/delete
, Вместо этого используйте умные указатели:
unique_ptr<S> new_S()
{
return std::make_unique<S>({{1}, {2}, {3}});
}
make_unique
поставляется с C ++ 14, вы можете легко свернуть свой собственный, если у вашей библиотеки его еще нет.
Обновить:
Чтобы ответить на ваш вопрос о времени жизни объекта: В new_S
у вас есть в основном 4 или 5 объектов:
s
это собственный объект.Теперь что происходит:
s
инициализируется временным вызывающим конструктором перемещения вектора. После этого временный пустой и s
владеет частью памяти с Ts_
, параметр перемещен. Это означает, s_
получает движение построено из временного (в вашем письме) или из s
(в моем письме). После этого временный /s
пусты и s_
владеет порцией памяти, выделенной на шаге 1.s_
правильно построен, и это действительный объект. Объект X
становится только «недействительным» при перемещении, т.е. при вызове move(X)
, Объект Y
вы строите, перемещая другой объект X
к нему (имеется в виду: создать его с помощью auto Y = move(X);
) никогда не является недействительным Инвалидирование объектов в конструкции было бы крайне плохо и бесполезно, C ++ был бы неработающим языком.
Других решений пока нет …