简体   繁体   English

没有默认构造函数的动态数组创建

[英]Dynamic array creation without default constructor

Disclaimer: I already know that raw arrays are not first class elements in C++ and that in many places, we are expected to replace them with vectors.免责声明:我已经知道原始数组不是 C++ 中的第一类元素,并且在许多地方,我们希望用向量替换它们。 But I still hope an other way...但我还是希望换一种方式...

Context:语境:

I am trying to build a multi-dimensional container library using contiguous data instead of vectors of vectors.我正在尝试使用连续数据而不是向量的向量来构建多维容器库。 A simple analogy is a 2D C array versus an array of pointers.一个简单的类比是 2D C 数组与指针数组。 The multi-dimensional part is handled as proxy classes over a 1D array.多维部分作为一维数组上的代理类处理。 It implies the use of proxy iterators but my current problem is the handling of the underlying 1D array.这意味着使用代理迭代器,但我当前的问题是底层一维数组的处理。

Ideally, that 1D array could use either static or automatic memory (and should not be freed after use) or private dynamic memory that should be.理想情况下,该一维数组可以使用静态或自动内存(并且不应在使用后释放)或应该使用的私有动态内存。 So far so good, I currently use a boolean ( owning ) to remember whether the array should be deleted.到目前为止一切顺利,我目前使用一个布尔值( owning )来记住是否应该删除数组。 I need to manually manage that memory, because I want sub-arrays to re-use the memory of their containers and cannot use the copy semantics of standard containers.我需要手动管理该内存,因为我希望子数组重新使用其容器的内存,而不能使用标准容器的复制语义。

Problem:问题:

If the underlying data type has a default contructor, everything is fine, I can safely build a dynamic array with new[] , and later free it with delete[] .如果底层数据类型具有默认构造函数,则一切正常,我可以安全地使用new[]构建动态数组,然后使用delete[]释放它。 But I also wonder whether it could be possible to only require a copyable type, and initialize the array with a default value (what std::vector can do).但我也想知道是否可以只需要一个可复制的类型,并用默认值初始化数组( std::vector可以做什么)。

Question:问题:

How can I build a dynamic array of a non default constructible objects and instead use copy initialization from a default value ?如何构建非默认可构造对象的动态数组,而是使用默认值的复制初始化?

Current research:目前的研究:

Provided a default ctor is available for class T, I can write:如果类 T 有一个默认的构造函数,我可以写:

    template <typename T>
    class Holder
    {
        size_t sz;         // size of the array
        bool owning;       // true if the array should be deleted
        T* data;           // pointer to the underlying array

    public:
        // builds an array of default initialized data
        Holder(size_t sz) : sz(sz), owning(true) {
            data = new T[sz];
        }

        // uses an existing array. Do not own it by default but can steal
        // it if own is true
        Holder(T* data, size_t sz, bool own=false) : sz(sz),
            owning(own), data(data) {};

        // builds an array of data initialized from a default value
        Holder(const T&value, size_t sz) : sz(sz), owning(true) {
            // what can be done here if no default ctor is available?
        }

        ~Holder() {
            if (owning) {
                delete[] data;
            }
        }

        // Copy ctor. Will borrow the original array
        Holder(const Holder<T>& other) : sz(other.sz), owning(false), data(other.data){}

        // Move ctor
        Holder(Holder&& other) : sz(other.sz), owning(other.owning) {
            data = other.data;
            other.data = nullptr;
            other.owning = false;
        }
        // assignment operators and accessors omitted for brievety
        ...
    };

I also know that I can safely fill an unitialized array with std::uninitialized_fill , and later destroy its objects with std::destroy but I am unsure of how to correctly use that and whether it is compatible with new[] and delete[] .我也知道我可以安全地用std::uninitialized_fill填充一个std::uninitialized_fill数组,然后用std::destroy销毁它的对象,但我不确定如何正确使用它以及它是否与new[]delete[]兼容. Said differently can I just delete an array allocated with operator new[] and initialized with uninitialized_fill ?换句话说,我可以delete一个用operator new[]分配并用uninitialized_fill的数组吗?

I am unsure of how to correctly use that and whether it is compatible with new[] and delete[] .我不确定如何正确使用它以及它是否与new[]delete[]兼容。

It isn't compatible with new T[] , but it is compatible with new char[] .它与new T[]不兼容,但与new char[]兼容。

template <typename T>
class Holder
{
    size_t sz;         // size of the array
    bool owning;       // true if the array should be deleted
    T* data;           // pointer to the underlying array

    using storage_t = std::aligned_storage_t<sizeof(T), alignof(T)>;

    static T* alloc(size_t sz) { // or just use an Allocator
        return reinterpret_cast<T*>(reinterpret_cast<char*>(new storage_t[sz])); 
    }

public:
    // builds an array of default initialized data
    Holder(size_t sz) requires std::default_initializable<T> : sz(sz), owning(true), data(alloc(sz)) {
        std::uninitialized_default_construct_n(data, sz);
    }

    // uses an existing array. Do not own it by default but can steal
    // it if own is true
    // This is now suspect, we should take a deleter here.
    // Holder(T* data, size_t sz, bool own=false) : sz(sz),
    //     owning(own), data(data) {};

    // uses an existing array. Do not own it
    Holder(T* data, size_t sz) : sz(sz), owning(false), data(data) {};

    // uses an existing array. Do not own it
    template <size_t N>
    Holder(T (&data)[N]) : sz(N), owning(false), data(data) {};

    // builds an array of data initialized from a default value
    Holder(const T&value, size_t sz) requires std::copy_constructible<T> : sz(sz), owning(true), data(alloc(sz)) {
        std::uninitialized_fill_n(data, sz, value);
    }

    ~Holder() {
        if (owning) {
            std::destroy_n(data, sz);
            delete[] reinterpret_cast<storage_t*>(data);
        }
    }

    // Copy ctor. Will borrow the original array
    Holder(const Holder<T>& other) : sz(other.sz), owning(false), data(other.data){}

    // Move ctor
    Holder(Holder&& other) : data(std::exchange(other.data, nullptr)) sz(other.sz), owning(std::exchange(other.owning, false)) {
    }
    // assignment operators and accessors omitted for brievety
    ...
};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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