与其所有者一起分配阵列的正确方法

Proper way of allocating array together with its owner

本文关键字:方法 阵列 分配 所有者 一起      更新时间:2023-10-16

我正在尝试动态分配一个通用类型的数组以及一种原始控制块。将此作为此"控制块"的检查代码:

template<class T>
struct my_array{
    T* arr;
    unsigned size;
};

为了避免多次分配,我尝试只调用分配new一次。这是我想出的代码:

template<class T>
my_array<T> *alloc_new_array(unsigned size){
    unsigned align_mismatch = sizeof(my_array<T>) % alignof(my_array<T>);
    unsigned array_size = size * sizeof(T);
    unsigned struct_size = sizeof(my_array<T>) + align_mismatch ? 
        alignof(my_array<T>) - align_mismatch : 0; 
    char *memory = new char[array_size + struct_size];
    my_array<T> *arr = new (memory) my_array<T>;
    arr->arr = new (memory + struct_size) T[size];
    arr->size = size;
    return arr;
}

我关心的是:

  • 正确性 - 我想我照顾了结构填充,但我可能缺少一些东西。我是否正确计算了它,无论平台如何,它都能正常工作吗?
  • 符合标准 - 我不会违反任何C++规则并导致 UB?我知道我在这里做一些指针魔法,我不确定一切是否完全合法

举个例子:

#include <iostream>
#include <new>
#include <memory>
#include <numeric>
template<class T>
struct alignas(T) WithArray {
    unsigned const size_;
    static void* operator new(size_t size, unsigned elements) {
        return ::operator new(size + elements * sizeof(T));
    }
    static void operator delete(void* p, size_t /*size*/, unsigned /*elements*/) {
        return ::operator delete(p);
    }
    static void operator delete(void* p) {
        return ::operator delete(p);
    }
    T* get_elements() { return reinterpret_cast<T*>(this + 1); }
    T* begin() { return get_elements(); }
    T* end() { return get_elements() + size_; }
    WithArray(unsigned elements)
        : size_(elements)
    {
        std::uninitialized_default_construct_n(get_elements(), size_);
    }
    ~WithArray() {
        std::destroy_n(get_elements(), size_);
    }
    WithArray(WithArray const&) = delete;
    WithArray& operator=(WithArray const&) = delete;
};
int main() {
    unsigned elements = 10;
    std::unique_ptr<WithArray<int>> a(new (elements) WithArray<int>(elements));
    for(int& elem : *a)
        std::cout << elem << ' ';
    std::cout << 'n';
    std::iota(a->begin(), a->end(), 0);
    for(int& elem : *a)
        std::cout << elem << ' ';
    std::cout << 'n';
}

输出:

0 0 0 0 0 0 0 0 0 0 
0 1 2 3 4 5 6 7 8 9 

alignas(T) + reinterpret_cast<T*>(this + 1) 是 C99 灵活阵列成员的C++版本。