C ++ Move Semantics: обработка объектов конца жизни как rvalues ​​[duplicate]

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)
5
задан André Harder 19 June 2018 в 00:19
поделиться

1 ответ

Компилятор не разрешен , чтобы произвольно решить преобразовать имя lvalue в значение r, которое нужно перенести из. Он может только делать это там, где это позволяет C ++-стандарт. Например, в выражении return (и только когда его return <identifier>;).

*to_be_filled = v; всегда будет выполнять копию. Даже если это последний оператор, который может получить доступ к v, он всегда является копией. Компиляторы не могут изменить это.

Мое понимание заключается в том, что return v является O (1), так как NRVO (по сути) делает v в r-значение, которое затем использует std :: vector-move-constructor.

Это не так, как это работает. NRVO полностью устранит ход / копию. Но способность return <identifier>; быть rvalue не является «оптимизацией». На самом деле это требование , что компиляторы рассматривают их как rvalues.

У компиляторов есть выбор относительно копирования. У компиляторов нет выбора о том, что делает return <identifier>;. Таким образом, вышеупомянутое будет либо вообще не двигаться (если произойдет NRVO), либо будет перемещать объект.

Есть ли тонкая причина, почему бы нет?

One причина, по которой это не допускается, заключается в том, что местоположение инструкции не должно произвольно изменять то, что делает этот оператор. См., return <identifier>; всегда будет перемещаться из идентификатора (если это локальная переменная). Неважно, где это находится в функции. В силу того, что мы являемся оператором return, мы знаем , что если выполняется return, после его выполнения ничего не будет.

Это не относится к произвольным операторам. Поведение выражения *to_be_filled = v; не должно изменяться в зависимости от того, где это происходит в коде. Вы не сможете превратить переход в копию только потому, что добавили еще одну строку в функцию.

Еще одна причина заключается в том, что произвольные утверждения могут быть действительно сложными очень быстро. return <identifier>; очень проста; он копирует / перемещает идентификатор в возвращаемое значение и возвращается.

В отличие от этого, что происходит, если у вас есть ссылка на v, и каким-то образом используется to_be_filled. Конечно, что не может произойти в вашем случае, но как насчет других, более сложных случаев? Последнее выражение может быть, по-видимому, прочитано из ссылки на перемещенный объект.

Это намного сложнее сделать в случаях return <identifier>;.

8
ответ дан Nicol Bolas 17 August 2018 в 11:21
поделиться
  • 1
    Они могли использовать правило as-if, если copy-ctor не делает ничего интересного. В отладчике он не должен наблюдаться. – o11c 16 June 2018 в 00:47
  • 2
    @ o11c: Если операции копирования и являются тривиальными (т. е. не наблюдаемыми), то это фактически не имеет значения; это сделало бы memcpy в любом случае. Но с нетривиальным движением (например, vector) это наблюдаемое поведение. – Nicol Bolas 16 June 2018 в 00:57
  • 3
    это возможно только в том случае, если интересна копия / перемещение содержимого содержимого . Это позволяет оптимизировать новый + memcpy + delete. – o11c 16 June 2018 в 07:26
  • 4
    @ o11c: распределение является наблюдаемым поведением, благодаря Allocator параметру vector. И если бы это был какой-то тип my_vector вместо std::vector, выбор был бы непосредственно наблюдаемым. Компилятор не может вызывать конструктор перемещения здесь. Период. – Nicol Bolas 16 June 2018 в 13:16
  • 5
    @NicolBolas: Я исправил свою формулировку в отношении NRVO (извините, что цитата в вашем ответе немного устарела - я чувствую, что это лучше, чем оставлять неточность, а затем путать будущих читателей). – André Harder 19 June 2018 в 00:30
Другие вопросы по тегам:

Похожие вопросы: