unique_ptr: каков эффект сброса вызова перед назначением - PullRequest
3 голосов
/ 14 февраля 2020

В c ++ 14, в чем разница между назначением существующего unique_ptr:

    std::unique_ptr<double> p = std::make_unique<double>(1.0);
    p = std::make_unique<double>(2.0);

и первым вызовом сброса перед назначением ему:?

    std::unique_ptr<double> p = std::make_unique<double>(1.0);
    p.reset();
    p = std::make_unique<double>(2.0);

Я подумал добавление .reset() перед присваиванием не окажет большого влияния на код, но то, что без reset(), похоже, производит другой (и более) код ассемблера при компиляции с -O3. Проверьте код онлайн здесь:

https://godbolt.org/z/mBApWH

https://godbolt.org/z/JfStmC

Ответы [ 2 ]

2 голосов
/ 14 февраля 2020

Похоже, есть возможность для улучшения в оптимизаторе G CC.

Во второй версии мы получаем

        call    operator new(unsigned long)
        mov     QWORD PTR [r12], 0                     ; [r12] is 0
        mov     esi, 4
        mov     rdi, rax
        call    operator delete(void*, unsigned long)
        mov     edi, 4
        call    operator new(unsigned long)
        mov     rdi, QWORD PTR [r12]                   ; rdi=[r12] == 0 (duh)
        mov     DWORD PTR [rax], 1111
        mov     QWORD PTR [r12], rax
        test    rdi, rdi                               ; unnecesary test
        je      .L1                                    ; branch always taken
        mov     esi, 4                                 ; unreachable code
        call    operator delete(void*, unsigned long)  ;
.L1:

лязг 9 на с другой стороны, производит гораздо меньший код для второй версии, поскольку он способен исключить первую new / delete.

        push    rbx
        mov     rbx, rdi
        mov     qword ptr [rdi], 0
        mov     edi, 4
        call    operator new(unsigned long)
        mov     dword ptr [rax], 1111
        mov     qword ptr [rbx], rax
        mov     rax, rbx
        pop     rbx
        ret
1 голос
/ 14 февраля 2020

Я полагаю, что большинство различий между выходными данными компилятора связано с тем, что для одного из двух фрагментов удалось оптимизировать больше материала. В конце концов, вы просто добавляете пару констант в переменную. Если мы хотим сделать работу оптимизатора более сложной, выходные данные почти идентичны . Там компилятор не имеет представления о том, как работает foo, и должен выполнить оба вызова к нему и добавить результаты к x, нет места, чтобы быть умным.

Чтобы ответить на ваш вопрос, разница невелика. Оператор присваивания перемещения unique_ptr в любом случае освобождает память, поэтому вызывает reset до того, как она станет избыточной. Но, как видно из моей ссылки, компилятор может пропустить эту операцию, если он знает, что указатель был сброшен.

Однако вызов reset before может быть полезен, если память, удерживаемая указателем, будет освобождена до выделения новая память, тем самым уменьшая объем памяти программы.

...