Я работаю над старым кодом, который использует ATL CComBSTR
тип. Я изменяю его так, чтобы он компилировался с использованием Visual C ++ Express Edition, который не поставляется с ATL. Я использовал только очень маленькое подмножество CComBSTR
Делать это довольно просто.
Однако при распределении BSTR
Блок памяти, мне нужно заполнить первые четыре байта с префиксом длины 4 байта. Я обеспокоен тем, что если я использую new char[size]
выражение, чтобы выделить память для строки, что я буду вызывать ошибки выравнивания из-за выделенного char
массив не имеет правильного выравнивания для четырехбайтового префикса.
Есть ли в стандарте что-либо, что указывает, какие требования для выравнивания возвращаются значения new
иметь? Все, что я вижу в C ++ 11:
5.3.4 / 1 [expr.new] Это зависит от реализации, поддерживаются ли типы с выравниванием (3.11).
3.11 / 6 [basic.align] Требование выравнивания для полного типа можно запросить с помощью выражения alignof (5.3.6). Кроме того, типы char, подписанный символ и неподписанный символ должны иметь самое слабое требование выравнивания. [Примечание: это позволяет использовать типы символов в качестве базового типа для выровненной области памяти (7.6.2). — Конечное примечание]
Я нахожу это немного запутанным — «самое слабое требование выравнивания» говорит мне «наименее строгое ограничение на выравнивание», но примечание под этим, похоже, указывает на то, что стандарт означает противоположное.
Я в безопасности, используя new char[sizeof(uint32_t) + 2*(length + 1)]
буфер как BSTR
как это?
РЕДАКТИРОВАТЬЯ только что понял, что в этом конкретном случае BSTR
необходимо использовать SysAllocString для того, чтобы выделить строку в любом случае; но я все еще интересуюсь ли это нормально использовать new
в этом случае.
5.3.4 / 1 [expr.new]
Это зависит от реализации, поддерживаются ли типы с выравниванием (3.11).
Одна важная вещь здесь: over-aligned
означает более выровненный, чем любой встроенный тип. Например, на 64-битной машине указатели обычно выровнены на 8 байтов, и, таким образом, на этих машинах выравнивание означает, что выравнивание строго больше 8.
Следовательно, over-aligned
имеет значение только при использовании векторных типов, таких как те, которые необходимы для инструкций SSE или AVX или некоторых вариантов C / C ++ (например, Open CL). В повседневном программировании типы, которые вы создаете из встроенных типов, никогда не переопределяются.
§3.11 Выравнивание [basic.align]
3 / расширенное выравнивание представлен выравниванием больше, чем
alignof(std::max_align_t)
, Это определяется реализацией, поддерживаются ли какие-либо расширенные выравнивания и контексты, в которых они поддерживаются (7.6.2). Тип с расширенным требованием выравнивания является над выравниванием тип.9 / Если запрос на конкретное расширенное выравнивание в конкретном контексте не поддерживается реализацией, программа является некорректной. Кроме того, запрос на выделение динамического хранилища во время выполнения, для которого запрошенное выравнивание не может быть выполнено, должен рассматриваться как ошибка выделения.
Кроме того, это обычно для new
вернуть память в соответствие alignof(std::max_align_t)
, Это потому что регулярный ::operator new
знает только размер объекта, который нужно выделить, а не его выравнивание, и, следовательно, должен удовлетворять самым строгим требованиям выравнивания, возможным в программе.
С другой стороны, остерегайтесь char
массив расположен в стеке, нет никакой гарантии, каким будет его выравнивание.
Это деталь реализации, но MSVC использует распределители операционной системы. HeapAlloc () для размещения CRT, CoTaskMemAlloc () для оболочек типа COM, таких как _bstr_t. Они оба выровнены по 8, как в 32-битном, так и в 64-битном коде.
Вы никогда не должны выделять память для BSTR с новый оператор, COM-распределитель должен использоваться, чтобы гарантировать, что они освобождаются, используя надлежащую кучу. Важно в любом сценарии взаимодействия, где используется BSTR, это стандартный тип автоматизации. CoTaskMemAlloc / Free () требуется, но всегда используйте вспомогательные функции BSTR, чтобы гарантировать их правильную инициализацию. SysAllocString () и SysFreeString (). Используйте SysAllocStringLen () для работы со строками, содержащими встроенные нули.
Никогда не пытайтесь использовать функции управления памятью C ++ для BSTR — они должны быть распределены только с использованием SysAllocString()
семейные функции. Это гарантирует, что тот, кто получает BSTR
можешь использовать SysFreeString()
и другие функции семьи по полученным BSTR
, Если вы нарушите это требование, ваша программа столкнется с неопределенным поведением.