新的重载运算符,具有较小的默认对齐方式 [英] Overloading operator new with smaller default alignment

查看:57
本文介绍了新的重载运算符,具有较小的默认对齐方式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

C ++ 17引入了动态内存对齐数据的分配

C++17 introduced Dynamic memory allocation for over-aligned data

除了现有的 std :: max_align_t (基本对齐方式)之外,它还添加了 __ STDCPP_DEFAULT_NEW_ALIGNMENT __ 操作员新保证的最小对齐方式.

Beside the existing std::max_align_t, the fundamental alignment, it added __STDCPP_DEFAULT_NEW_ALIGNMENT__ the minimal alignment that the operator new guarantees.

使用MSVC2017 64位编译时,这些常量将导致大小为8的 std :: max_align_t 和大小为16的 __ STDCPP_DEFAULT_NEW_ALIGNMENT __ .

With MSVC2017 64bit compilation, these constants result in a std::max_align_t of size 8 and __STDCPP_DEFAULT_NEW_ALIGNMENT__ of size 16.

但是,如 cppreference:运算符new-全局替换.

查看所有文档,尚不清楚我是否允许此函数提供新的默认对齐方式,如果允许,是否允许我们重新定义此常量.

Looking at all of the documents, it's unclear to me if this function is allowed to provide a new default alignment and if so, if we are allowed to redefine this constant.

一个示例:

#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的类.

The reason I'm asking this, is because I'm investigating crashes in an MSVC program that is now being compiled with Clang. Here we noticed that clang uses CPU instructions that rely on this 16 bit alignment in order to initialize a class of size 8.

推荐答案

根据

According to N4659 (last public draft for C++17):

6.7.4p3:

在C ++程序中定义的任何分配和/或释放函数,包括库中的默认版本,应符合6.7.4.1和6.7.4.2中指定的语义.

Any allocation and/or deallocation functions defined in a C++program, including the default versions in the library, shall conform to the semantics specified in 6.7.4.1 and 6.7.4.2.

6.7.4.1p2:

6.7.4.1p2:

...返回的指针应适当对齐,以便可以转换为指向任何合适的完整对象类型的指针(21.6.2.1)然后用于访问存储中的对象或数组已分配(直到通过调用显式释放存储相应的释放功能)....

... The pointer returned shall be suitably aligned so that it can be converted to a pointer to any suitable complete object type (21.6.2.1) and then used to access the object or array in the storage allocated(until the storage is explicitly deallocated by a call to a corresponding deallocation function). ...

19.8p1:

以下宏名称应由实现定义:... __ STDCPP_DEFAULT_NEW_ALIGNMENT __ 类型为std :: size_t的整数文字,其值是通过调用保证的对齐方式 operator new(std :: size_t) operator new [](std :: size_t)....

The following macro names shall be defined by the implementation: ... __STDCPP_DEFAULT_NEW_ALIGNMENT__ An integer literal of type std::size_t whose value is the alignment guaranteed by a call to operator new(std::size_t) or operator new[](std::size_t). ...

19.8p4:

如果此子节中有任何预定义的宏名称,或者标识符 defined #define #undef 的主题预处理指令,行为未定义....

If any of the pre-defined macro names in this subclause, or the identifier defined, is the subject of a #define or a #undef preprocessing directive, the behavior is undefined. ...

因此,您无法在程序内更改 __ STDCPP_DEFAULT_NEW_ALIGNMENT __ 值,并且如果您的分配函数是针对 alignas(__ STDCPP_DEFAULT_NEW_ALIGNMENT __)类型8的类型调用的,则无法检测到,但是您仍然需要返回适当对齐的指针.

So, you cannot change the __STDCPP_DEFAULT_NEW_ALIGNMENT__ value inside your program, and if your allocation function is called for alignas(__STDCPP_DEFAULT_NEW_ALIGNMENT__) type of size 8, you cannot detect that, but you still need to return a suitably aligned pointer.

不过,您可以使用 -fnew-alignment 编译器选项更改clang自身定义的 __ STDCPP_DEFAULT_NEW_ALIGNMENT __ 值.不确定是否对您有帮助.

Nonetheless, you can change the __STDCPP_DEFAULT_NEW_ALIGNMENT__ value as defined by clang itself using -fnew-alignment compiler option. Not sure if it helps in your case.

这篇关于新的重载运算符,具有较小的默认对齐方式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆