Существует ли какой-либо компилятор, в котором требования к макету для стандартных типов макетов также не применяются к тривиально копируемым типам? В частности, критическим правилом является то, что указатель на тип является указателем на его первый член (где базовый класс будет считаться предшествующим производному классу). То есть адрес типа будет таким же, как и его базовый тип.
В коде есть какой-нибудь распространенный компилятор, в котором следующее не будет работать на самом деле. Мне кажется, что это обычная практика, поэтому я удивился, что это не было стандартизировано в C ++ 11.
struct base { int a; /* is a trivial class*/ };
struct derived : public base { int b; /*still a trivial class*/ }
void copy( base * a, base * b, size_t len )
{
memcpy( a, b, len );
}
...
derived d1, d2;
copy( &d1, &d2, sizeof(derived) );
Я точно знаю, что это работает в GCC, и я верю, что это работает в MSVC (хотя я могу ошибаться). В каком неисторическом компиляторе вышеперечисленное не будет работать так, как задумано?
Расширенный пример
Приведенный выше пример демонстрирует фундаментальную проблему, но может не показывать намерение, которое могло бы ее решить. Вот немного более подробный пример. По сути, любой может вызвать «отправить», который поставит сообщение в очередь, а затем что-то отправит каждое сообщение, вернув его к реальному типу.
struct header { int len, id; }
struct derived : public header { int other, fields; }
void send( header * msg )
{
char * buffer = get_suitably_aligned_buffer( msg->len );
memcpy( buffer, msg, msg->len );
}
void dispatch( char * buffer )
{
header * msg = static_cast<header*>(buffer);
if( msg->id == derived_id )
handle_derived( static_cast<derived*>(msg) );
}
derived d;
d.len = sizeof(d);
d.id = deirved_id;
send( &d );
...
char * buffer = get_the_buffer_again();
dispatch( buffer );
В нем по-прежнему пропущено много аспектов, но показаны ключевые части.