def td_format(td_object):
seconds = int(td_object.total_seconds())
periods = [
('year', 60*60*24*365),
('month', 60*60*24*30),
('day', 60*60*24),
('hour', 60*60),
('minute', 60),
('second', 1)
]
strings=[]
for period_name, period_seconds in periods:
if seconds > period_seconds:
period_value , seconds = divmod(seconds, period_seconds)
has_s = 's' if period_value > 1 else ''
strings.append("%s %s%s" % (period_value, period_name, has_s))
return ", ".join(strings)
Компилятор не разрешен , чтобы произвольно решить преобразовать имя lvalue в значение r, которое нужно перенести из. Он может только делать это там, где это позволяет C ++-стандарт. Например, в выражении return
(и только когда его return <identifier>;
).
*to_be_filled = v;
всегда будет выполнять копию. Даже если это последний оператор, который может получить доступ к v
, он всегда является копией. Компиляторы не могут изменить это.
Мое понимание заключается в том, что return v является O (1), так как NRVO (по сути) делает v в r-значение, которое затем использует std :: vector-move-constructor.
blockquote>Это не так, как это работает. NRVO полностью устранит ход / копию. Но способность
return <identifier>;
быть rvalue не является «оптимизацией». На самом деле это требование , что компиляторы рассматривают их как rvalues.У компиляторов есть выбор относительно копирования. У компиляторов нет выбора о том, что делает
return <identifier>;
. Таким образом, вышеупомянутое будет либо вообще не двигаться (если произойдет NRVO), либо будет перемещать объект.Есть ли тонкая причина, почему бы нет?
blockquote>One причина, по которой это не допускается, заключается в том, что местоположение инструкции не должно произвольно изменять то, что делает этот оператор. См.,
return <identifier>;
всегда будет перемещаться из идентификатора (если это локальная переменная). Неважно, где это находится в функции. В силу того, что мы являемся операторомreturn
, мы знаем , что если выполняетсяreturn
, после его выполнения ничего не будет.Это не относится к произвольным операторам. Поведение выражения
*to_be_filled = v;
не должно изменяться в зависимости от того, где это происходит в коде. Вы не сможете превратить переход в копию только потому, что добавили еще одну строку в функцию.Еще одна причина заключается в том, что произвольные утверждения могут быть действительно сложными очень быстро.
return <identifier>;
очень проста; он копирует / перемещает идентификатор в возвращаемое значение и возвращается.В отличие от этого, что происходит, если у вас есть ссылка на
v
, и каким-то образом используетсяto_be_filled
. Конечно, что не может произойти в вашем случае, но как насчет других, более сложных случаев? Последнее выражение может быть, по-видимому, прочитано из ссылки на перемещенный объект.Это намного сложнее сделать в случаях
return <identifier>;
.
vector
) это наблюдаемое поведение. – Nicol Bolas 16 June 2018 в 00:57Allocator
параметруvector
. И если бы это был какой-то типmy_vector
вместоstd::vector
, выбор был бы непосредственно наблюдаемым. Компилятор не может вызывать конструктор перемещения здесь. Период. – Nicol Bolas 16 June 2018 в 13:16