作为一个大项目的一部分,我决定开发一个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。)
我的问题是如何处理破坏未初始化成员的情况?我最好接受成员需要默认构造函数吗?
答案 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;
}
}