C++17 引入过度对齐数据的动态内存分配
除了现有的std::max_align_t
,基本对齐,它补充说__STDCPP_DEFAULT_NEW_ALIGNMENT__
运算符 new 保证的最小对齐。
通过 MSVC2017 64 位编译,这些常量会产生std::max_align_t
尺寸为 8 且__STDCPP_DEFAULT_NEW_ALIGNMENT__
尺寸为 16。
然而,它可以否决运算符 new/free,如上所述cppreference:operator new - 全局替换.
查看所有文档,我不清楚是否允许该函数提供新的默认对齐方式,如果可以,是否允许我们重新定义该常量。
举例说明:
#include <new>
#include <iostream>
#include <cassert>
#include <cstdint>
#include <cstddef>
static_assert(alignof(std::max_align_t) == 8);
static_assert(__STDCPP_DEFAULT_NEW_ALIGNMENT__ == 16);
void * operator new(size_t size)
{
std::cout << "New operator overloading " << std::endl;
void * p = std::malloc((size == 8) ? 16 : size);
assert(std::uintptr_t(p)%16 == 0);
if (size == 8)
{
auto correctedPtr = std::uintptr_t(p) + 8;
return (void*)correctedPtr;
}
return p;
}
void operator delete(void * p)
{
std::cout << "Delete operator overloading " << std::endl;
if (std::uintptr_t(p)%16 != 0)
{
auto correctedPtr = std::uintptr_t(p) - 8;
std::free((void*)correctedPtr);
}
std::free(p);
}
namespace
{
struct D
{
double d;
};
}
int main(int, char**)
{
new D{};
return 0;
}
编译器资源管理器中的代码
我之所以问这个问题,是因为我正在调查正在使用 Clang 编译的 MSVC 程序中的崩溃情况。这里我们注意到 clang 使用依赖于 16 位对齐的 CPU 指令来初始化大小为 8 的类。
根据N4659(C++17 的最新公开草案):
6.7.4p3:
C++ 程序中定义的任何分配和/或释放函数,
包括库中的默认版本,应符合
6.7.4.1 和 6.7.4.2 中指定的语义。
6.7.4.1p2:
...返回的指针应适当对齐,以便可以
转换为指向任何合适的完整对象类型的指针(21.6.2.1)
然后用于访问存储中的对象或数组
已分配(直到通过调用显式释放存储
相应的释放函数)。 ...
19.8p1:
以下宏名称应由实现定义:
...__STDCPP_DEFAULT_NEW_ALIGNMENT__
std::size_t 类型的整数文字,其值是通过调用保证的对齐operator new(std::size_t)
or operator new[](std::size_t)
.
...
19.8p4:
如果本子条款中的任何预定义宏名称,或
标识符defined
, 是一个主题#define
or a #undef
预处理指令,行为未定义。
...
因此,您无法更改__STDCPP_DEFAULT_NEW_ALIGNMENT__
程序内的值,以及如果调用分配函数alignas(__STDCPP_DEFAULT_NEW_ALIGNMENT__)
大小为 8 的类型,您无法检测到这一点,但您仍然需要返回一个适当对齐的指针。
尽管如此,您可以更改__STDCPP_DEFAULT_NEW_ALIGNMENT__
由 clang 本身定义的值-fnew-alignment
编译器选项。不确定它对您的情况是否有帮助。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)