void *pMem = malloc(realSize); // вызвать malloc для получения памяти
if(!pMem) throw(bad_alloc);
// записать сигнатуру в первое и последнее слово выделенного блока
*(static_castintpMem)) = signature;
*(reinterpret_castint*(static_castByte*(pMem)+realSize-sizeof(int))) =
signature;
// вернуть указатель на память сразу за начальной сигнатурой
return static_castByte*(pMem)+sizeof(int);
}
Большинство недостатков этой версии оператора new связаны с тем, что он не вполне соответствует соглашениям C++ относительно функций с таким именем. Например, в правиле 51 объясняется, что все операторы new должны включать цикл вызова функции-обработчика new, чего этот вариант не делает. Этому соглашению посвящено правило 51, поэтому сейчас я хочу сосредоточиться на более тонком моменте:
Многие компьютерные архитектуры требуют, чтобы данные конкретных типов были размещены в памяти по вполне определенным адресам. Например, архитектура может требовать, чтобы указатели размещались по адресам, кратным четырем (то есть были выровнены на границу четырехбайтового слова), а данные типа double начинались с адреса, кратного восьми. Если не придерживаться этого соглашения, то возможны аппаратные ошибки во время исполнения. Другие архитектуры более терпимы, хотя и могут демонстрировать более высокую производительность, если удовлетворены требования выравнивания. Например, на архитектуре Intel x86 значения типа double могут быть выровнены по границе любого байта, но доступ к ним будет значительно быстрее, если они выровнены по восьмибайтовым границам.
Выравнивание важно, потому что C++ требует, чтобы все указатели, возвращаемые оператором new, были выровнены для
Внимание к подобным деталям отличает менеджеры памяти профессионального качества от тех, что делают на скорую руку программисты, вынужденные отвлекаться на другие задачи. Написать собственный менеджер памяти, который почти работает, достаточно просто. Написать такой, который работает
Во многих случаях ее нет. Некоторые компиляторы имеют переключатели, позволяющие отлаживать и протоколировать работу функций управления памятью. Поверхностное знакомство с документацией по вашему компилятору может исключить необходимость в написании собственных версий new и delete. На многих платформах доступны коммерческие продукты, позволяющие заменить функции управления памятью, поставляемые с компиляторами. Чтобы воспользоваться их расширенной функциональностью и (предположительно) повышенной производительностью, придется лишь заново компоновать программу (ну и, само собой, заплатить).