这里有人用过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

其他回答

这里是c++ in-place构造函数的杀手级用法:对齐缓存线,以及其他2边界的幂。以下是我的超快速指针对齐算法,使用5个或更少的单周期指令,达到2边界的任意幂:

/* Quickly aligns the given pointer to a power of two boundary IN BYTES.
@return An aligned pointer of typename T.
@brief Algorithm is a 2's compliment trick that works by masking off
the desired number in 2's compliment and adding them to the
pointer.
@param pointer The pointer to align.
@param boundary_byte_count The boundary byte count that must be an even
power of 2.
@warning Function does not check if the boundary is a power of 2! */
template <typename T = char>
inline T* AlignUp(void* pointer, uintptr_t boundary_byte_count) {
  uintptr_t value = reinterpret_cast<uintptr_t>(pointer);
  value += (((~value) + 1) & (boundary_byte_count - 1));
  return reinterpret_cast<T*>(value);
}

struct Foo { Foo () {} };
char buffer[sizeof (Foo) + 64];
Foo* foo = new (AlignUp<Foo> (buffer, 64)) Foo ();

这是不是让你的脸上露出了微笑(:)。我♥♥♥c++ 1x

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

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

如果你正在构建一个内核,它很有用——你把从磁盘或页表读取的内核代码放在哪里?你得知道该往哪里跳。

或者在其他非常罕见的情况下,比如当你有大量分配的空间,想要把几个结构放在彼此后面。它们可以这样打包,而不需要使用offset()操作符。不过,还有其他的技巧。

我也相信一些STL实现使用了新位置,比如std::vector。它们以这种方式为2^n个元素分配空间,而不需要总是realloc。

它可能在使用共享内存时很方便,在其他用途中…例如:http://www.boost.org/doc/libs/1_51_0/doc/html/interprocess/synchronization_mechanisms.html#interprocess.synchronization_mechanisms.conditions.conditions_anonymous_example

一般来说,放置新是为了摆脱“正常新”的分配成本。

我使用它的另一个场景是,我想要访问一个仍待构造的对象的指针,以实现每个文档的单例。