这里有人用过c++的“placement new”吗?如果有,为什么?在我看来,它只在内存映射硬件上有用。


当前回答

我还有一个想法(它对c++ 11有效)。

让我们看看下面的例子:

#include <cstddef>
#include <cstdio>

int main() {
    struct alignas(0x1000) A {
        char data[0x1000];
    };

    printf("max_align_t: %zu\n", alignof(max_align_t));

    A a;
    printf("a: %p\n", &a);

    A *ptr = new A;
    printf("ptr: %p\n", ptr);
    delete ptr;
}

使用c++ 11标准,GCC给出以下输出:

max_align_t: 16
a: 0x7ffd45e6f000
ptr: 0x1fe3ec0

PTR没有正确对齐。

对于c++ 17标准和更高级的标准,GCC给出了以下输出:

max_align_t: 16
a: 0x7ffc924f6000
ptr: 0x9f6000

PTR对齐正确。

据我所知,c++标准在c++ 17之前不支持过对齐的new,如果你的结构的对齐大于max_align_t,你就会遇到问题。 要在c++ 11中绕过这个问题,可以使用aligned_alloc。

#include <cstddef>
#include <cstdlib>
#include <cstdio>
#include <new>

int main() {
    struct alignas(0x1000) A {
        char data[0x1000];
    };

    printf("max_align_t: %zu\n", alignof(max_align_t));

    A a;
    printf("a: %p\n", &a);

    void *buf = aligned_alloc(alignof(A), sizeof(A));
    if (buf == nullptr) {
        printf("aligned_alloc() failed\n");
        exit(1);
    }
    A *ptr = new(buf) A();
    printf("ptr: %p\n", ptr);
    ptr->~A();
    free(ptr);
}

在这种情况下PTR是对齐的。

max_align_t: 16
a: 0x7ffe56b57000
ptr: 0x2416000

其他回答

我曾看到它被用作“动态类型”指针的轻微性能hack(在“引擎盖下”一节中):

但这是我用来获得小类型的快速性能的棘手技巧:如果所持有的值可以放入void*中,我实际上不需要分配一个新对象,而是使用placement new将其强制到指针本身。

Head Geek: BINGO! You got it totally - that's exactly what it's perfect for. In many embedded environments, external constraints and/or the overall use scenario forces the programmer to separate the allocation of an object from its initialization. Lumped together, C++ calls this "instantiation"; but whenever the constructor's action must be explicitly invoked WITHOUT dynamic or automatic allocation, placement new is the way to do it. It's also the perfect way to locate a global C++ object that is pinned to the address of a hardware component (memory-mapped I/O), or for any static object that, for whatever reason, must reside at a fixed address.

它被std::vector<>使用,因为std::vector<>通常分配比vector<>中的对象更多的内存。

我用它来存储带有内存映射文件的对象。 具体的例子是一个图像数据库,它处理大量的大图像(超过内存容量)。

我使用它来构造通过alloca()分配到堆栈上的对象。

无耻的宣传:我在这里写过博客。