Тривиально копируемый всегда псевдостандартный макет? - PullRequest
0 голосов
/ 17 марта 2012

Существует ли какой-либо компилятор, в котором требования к макету для стандартных типов макетов также не применяются к тривиально копируемым типам? В частности, критическим правилом является то, что указатель на тип является указателем на его первый член (где базовый класс будет считаться предшествующим производному классу). То есть адрес типа будет таким же, как и его базовый тип.

В коде есть какой-нибудь распространенный компилятор, в котором следующее не будет работать на самом деле. Мне кажется, что это обычная практика, поэтому я удивился, что это не было стандартизировано в 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 );

В нем по-прежнему пропущено много аспектов, но показаны ключевые части.

Ответы [ 2 ]

1 голос
/ 18 марта 2012

Да, люди занимались этим в C ++ до тех пор, пока существует единственное наследование.Да, это разумно.Нет, стандарт не поддерживается.Это универсально поддерживается?Возможно, но вы уже, кажется, знаете, что это не главное.Такого рода вопрос заключается в том, что стандартизация должна устранить.

К лучшему или худшему, C ++ действительно предоставляет решение этой проблемы, хотя и явно менее элегантно.

Проблема заключается в том, что нестатическийэлементы данных в производном классе не обязательно следуют тому же заполнению после элементов базы, как если бы они были вставлены непосредственно в базу.

Но union стандартных структур компоновки с общей начальной последовательностью (преднамеренно избегая наследования) действительно получает эту гарантию.

struct header { int len, id; }

union derived {
    struct {
        header h;
        int payload;
    } fmt1;

    struct {
        header h; // repetitive
        double payload;
    } fmt2;

    // etc for all message types
};

Структура может фактически отличаться, когда пустые базовые классы включаются многократно, особенно если первый элемент нестатических данных имеет тот же тип, что ипустой базовый класс.Причина, по которой наследование (до сих пор) не может этого сделать, заключается в том, что, возможно, они устали от написания особых случаев о пустых базах.

1 голос
/ 17 марта 2012

Я точно знаю, что это работает в GCC, и я верю, что это работает в MSVC (хотя я могу ошибаться).

Нет, нет. Вы запустили несколько примеров, которые не ломают на этих компиляторах. Это отличается от , зная «наверняка», что угодно.

Неопределенное поведение не определено. Следующая версия GCC может сломать ваш код. Следующая версия Visual Studio может сломать ваш код. Действительно, компиляция в release или с определенной оптимизацией может привести к поломке вашего кода.

Следование стандарту - это единственный способ «точно знать» что-либо о том, что вы получаете. То, что вы делаете, не является поведением, определяемым реализацией; это неопределенное поведение. Таким образом, вы не можете поверить, что получите последовательный разумный ответ, даже если он , кажется, работает.

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