Разница в разрешении копирования для тривиальных и нетривиальных типов - PullRequest
3 голосов
/ 08 февраля 2020

Я проверяю возможность копирования между тривиальными и нетривиальными типами, способными к копированию, когда возврат одной функции по значению напрямую передается по значению в другую функцию. Для нетривиального случая кажется, что объект передается напрямую, как и ожидалось, но для тривиального случая кажется, что выходной объект копируется в стек для создания объекта ввода для второй функции. У меня вопрос: почему?

Если это ожидается, это удивительно, поскольку нетривиально копируемый тип более эффективно передается между этими функциями.

Источник:

struct Trivial_Struct
{
    unsigned char bytes[ 4 * sizeof( void* ) ];
};

struct Nontrivial_Struct
{
    unsigned char bytes[ 4 * sizeof( void* ) ];
    Nontrivial_Struct( Nontrivial_Struct const& );
};

Trivial_Struct trivial_struct_source();
Nontrivial_Struct nontrivial_struct_source();
void trivial_struct_sink( Trivial_Struct );
void nontrivial_struct_sink( Nontrivial_Struct );

void test_trivial_struct()
{
    trivial_struct_sink( trivial_struct_source() );
}

void test_nontrivial_struct()
{
    nontrivial_struct_sink( nontrivial_struct_source() );
}

G CC Выходная сборка:

test_trivial_struct():
    sub     rsp, 40
    mov     rdi, rsp
    call    trivial_struct_source()
    push    QWORD PTR [rsp+24]
    push    QWORD PTR [rsp+24]
    push    QWORD PTR [rsp+24]
    push    QWORD PTR [rsp+24]
    call    trivial_struct_sink(Trivial_Struct)
    add     rsp, 72
    ret
test_nontrivial_struct():
    sub     rsp, 40
    mov     rdi, rsp
    call    nontrivial_struct_source()
    mov     rdi, rsp
    call    nontrivial_struct_sink(Nontrivial_Struct)
    add     rsp, 40
    ret

godbolt.org . Я попробовал G CC, Clang и MSVC; Мне легче читать ассемблер G CC, но все компиляторы, похоже, делают подобный код для тривиально копируемого случая.

Mis c:

  • Очевидно, что я могу случайно сделать Nontrivial_Struct тривиальным, если объявлю конструктор копирования внутри определения класса как Nontrivial_Struct( Nontrivial_Struct const& ) = default; если я добавлю Nontrivial_Struct::Nontrivial_Struct( Nontrivial_Struct const& ) = default; после определения класса, тогда оно останется нетривиальным.
  • Я могу изменить «4» на большие значения, такие как «64», и это все еще происходит .

Предположение:

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...