处理未初始化的数组

时间:2015-12-11 15:38:44

标签: c++ arrays memory-management

作为一个大项目的一部分,我决定开发一个C ++ c数组包装器,显然这可能只是一个std向量,但我已经学到了很多东西,并且它已经长大了我想进一步探讨几点。

code review上发布我的代码后,我增加了代码的复杂性。大多数情况下这改进了代码,但在此过程中我也遇到了一些新问题:

现在代码使用重载的新代码来避免默认初始化成员。

Simple_Array(size_type size) :
    _size(size),
    _data(static_cast<pointer>(::operator new(_size * sizeof(value_type))))
{}

template <
    class It,
    class = typename std::enable_if< std::is_constructible< value_type,
        typename std::iterator_traits<It>::value_type >::value >::type
>
Simple_Array(It first, It last) :
    Simple_Array(std::distance(first, last))
{
    for (iterator i = _data; first != last; ++first, ++i)
        new (i) value_type{*first};
}

因此,每个成员必须调用析构函数:

~Simple_Array() {
    for (iterator i = begin(); i != end(); ++i)
        i->~value_type();

    ::operator delete(_data);
}

如果你在破坏这种类型的过程中尝试创建Simple_Array<Simple_Array<int>>,如果没有初始化任何成员,那么这里的问题就会得到最好的说明,然后当未初始化的Simple_Array有它的析构函数时,它会启动使用未初始化的迭代器并导致各种问题。 (注意,begin()只返回_data,end()返回_data + _size。迭代器是Ty *,_data是Ty *(c数组),_size是std :: size_t。)

我的问题是如何处理破坏未初始化成员的情况?我最好接受成员需要默认构造函数吗?

1 个答案:

答案 0 :(得分:1)

不,您不需要要求对象是默认构造的。

你必须做的是分离内存分配和对象初始化的问题。

这是就地构造函数和析构函数的少数合法用法之一。

别忘了干净利落地处理析构函数!!

构造函数应该如下所示:

SimpleArray(Iter first, Iter last)
: _size(last - first)
, _data(allocate_aligned_uninitialised_memory()) // <- you need to figure this one out
{
   // now we have allocated memory by no copied objects...
   auto dest = &_data[0];
   try {
     while (first != last) {
       // in-place construction
       new (dest)(*first++);
       ++dest;
     }
   }
   catch(...) {
     // if one of the constructors threw, we must unwind the ones that didnt
     while (dest != first) {
       // in-place destruction
       --dest;
       dest->~dest();
     }
     // release the aligned memory
     release_aligned_memory(_data);

     // pass the exception on - we failed to construct
     throw;
   }
}