Рассмотрим следующее определение Foo
:
struct Foo {
uint64_t data;
};
Теперь рассмотрим следующее определение Bar
, которое имеет тот же элемент данных, что и Foo
, но имеет пусто деструктор, объявленный пользователем :
struct Bar {
~Bar(){} // <-- empty user-declared dtor
uint64_t data;
};
При использовании gcc 8.2 с -O2
функция copy_foo()
:
void copy_foo(const Foo* src, Foo* dst, size_t len) {
std::copy(src, src + len, dst);
}
приводит к следующемукод сборки:
copy_foo(Foo const*, Foo*, size_t):
salq $3, %rdx
movq %rsi, %rax
je .L1
movq %rdi, %rsi
movq %rax, %rdi
jmp memmove
.L1:
ret
Приведенный выше код сборки вызывает memmove()
, чтобы выполнить копирование смежных объектов Foo
.Однако функция ниже, copy_bar()
, которая точно так же, как copy_foo()
, но для Bar
объектов:
void copy_bar(const Bar* src, Bar* dst, size_t len) {
std::copy(src, src + len, dst);
}
генерирует следующий код сборки:
copy_bar(Bar const*, Bar*, size_t):
salq $3, %rdx
movq %rdx, %rcx
sarq $3, %rcx
testq %rdx, %rdx
jle .L4
xorl %eax, %eax
.L6:
movq (%rdi,%rax,8), %rdx
movq %rdx, (%rsi,%rax,8)
addq $1, %rax
movq %rcx, %rdx
subq %rax, %rdx
testq %rdx, %rdx
jg .L6
.L4:
ret
Этот ассемблерный код не вызывает memmove()
, но выполняет копирование само по себе.
Конечно, если вместо Bar
определено следующее:
struct Bar {
~Bar() = default; // defaulted dtor
uint64_t data;
};
Тогда обе функцииВ результате получается идентичный ассемблерный код, поскольку Foo
также имеет дефолтный деструктор.
Есть ли причина, по которой объявление пользователем пустого деструктора в классе не позволяет компилятору генерировать вызов для memmove()
для копирования смежныхобъекты этого класса?