Правильный способ распределения массива вместе с его владельцем

Обновить

April 2019

Просмотры

59 раз

1

Я пытаюсь динамически выделять массив общего типа наряду с такими примитивами блока управления. Возьмите это как образцовый код этого «блок управления»:

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;
}

Что меня беспокоит это:

  • Правильность - Я думаю, что я позаботилась о STRUCT дополнения, но может быть что-то мне не хватает. Разве я считаю это правильно, и он будет работать должным образом, независимо от платформы?
  • Соответствие стандартам - не я нарушу какое-либо правило C ++ и вызвать UB? Я знаю, что я делаю какой-то указатель магии здесь, и я не уверен, если все полностью легально

1 ответы

3

One example for you:

#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';
}

Output:

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) is the C++ version of C99 flexible array member.

Связанные вопросы