简体   繁体   中英

Properly allocate an array with placement new

I'm building a memory allocator and making use of placement new. Say I want to "place" 10 elements to an already allocated array on the heap.

First regular new allocates the necessary amount of Bytes on the heap, then i construct my WE objects at appropriate locations.

struct WE {
    WE() {
        std::cout << "WE default constructed\n";
    }
    ~WE() {
        std::cout << "WE default destructed\n";
    }

    double d;
    int i;
    char c;
};

Is the following usage of placement new correct?

Code compiles and output seems correct, but I have some doubts.

// 1. allocate
const int elements = 10;
int nbytes = elements * sizeof(WE);
char* memory = new char[nbytes];
WE* pB = (WE*)memory;
int step = sizeof(WE);
// 2. construct
for (int i = 0; i < nbytes; i += step)
    new (pB + i) WE();
// 3. process
for (int i = 0; i < nbytes; i += step)
    pB[i].i = i * 2;
for (int i = 0; i < nbytes; i += step)
    std::cout << '[' << i << ']' << '=' << pB[i].i << '\n';
// 4. destruct
for (int i = 0; i < nbytes; i += step)
    pB[i].~WE();
// 5. deallocate
delete[] memory;
pB = nullptr;
memory = nullptr;

If all is well with question above, then allow me an addition question, how would I align this array on an arbitrary byte boundary? Say I want alignment at a sizeof(WE) which is 16 (and not at alignof(WE) which is 8 ). Would this modification: alignas(sizeof(WE)) char* memory = new char[nbytes]; be enough to do the trick? I've also heard of std::aligned_storage . I'm not sure whether it could provide any benefits. (If the second question confused you, or if I've messed things up on part 1, forget about it.) Thanks in advance.

For objects construction (placement new), you can either iterate byte/char-wise:

for (int i = 0; i < nbytes; i += step) new (memory + i) WE();

or element-wise:

for (int i = 0; i < elements; i++) new (pB + i) WE();

In the remaining loops, where you access the elements, you need to use the second option.

As for alignment, dynamic memory allocation returns a memory chunk aligned at alignof(std::max_align_t) (C++11). The exemplary value is 16 (GCC/x86_64), which is what you want, but this value is of course not guaranteed by the Standard.

If I am not wrong, before C++17 operator new cannot allocate memory for over-aligned objects directly and std::aligned_storage does not help here. From C++17, there are special versions of operator new that accept alignment information, see: https://en.cppreference.com/w/cpp/memory/new/operator_new .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM