C ++值初始化自定义容器的项

时间:2018-12-29 07:54:19

标签: c++ c++11 containers value-initialization

让我们以自定义vector实现为例:

template<typename Object>
class myVector {
public:
    explicit myVector(int size = 0) :
        _size{ size },
        _capasity{ size + SPARE_CAPACITY }
    {
        _buff = new Object[_capasity];
        if (_size > 0) {
            for (int i = 0; i < _size; i++) {
                //_buff[i] = 0;
            }
        }
    }

// more code

private:
    Object * _buff = nullptr;
    int _size;
    int _capasity;
};

所以我的问题是,如何将myVector进行值初始化,以防万一我将其初始化为:

int main() {
    myVector<int> v02(5);                   
}

在这里,它包含5个int值,因此我需要将其全部为零;与其他类型相同。我注释了_buff[i] = 0;,因为它专门针对int。请给我一些提示。

2 个答案:

答案 0 :(得分:3)

就这么简单

for (int i = 0; i < _size; i++)
    _buff[i] = Object{};

或者,您可以摆脱循环并在此处添加一对{}(或()):

_buff = new Object[_capasity]{};
//                           ^^

但是此选项将对所有_capasity个对象进行值初始化,而不是@bipll所指出的第一个_size个对象。


此外,请注意,如果您想模仿std::vector的行为,则需要分配原始存储空间(可能是std::aligned_storage)并手动调用构造函数(通过placement-new)和析构函数。

如果Object是类类型,则_buff = new Object[_capasity];会为所有_capasity对象调用默认构造函数,而不是像_size那样为第一个std::vector对象调用默认构造函数。

答案 1 :(得分:1)

请注意,致电时

        _buff = new Object[_capasity];

(顺便说一句,为什么要将此初始化从init-list中移到构造函数主体中?)您已经具有默认初始化的_capasity对象。默认初始化在这里具有以下效果:虽然标量类型的元素将保持未初始化(并从UB读取),但对于类类型,您已经调用了_capasity构造函数。

为避免不必要的构造,您可以选择以下选项:

  1. 使用std::aligned_alloc分配未初始化的内存:

    explicit myVector(std::size_t size = 0) :
        size_{ size }
        , capacity_{ size + SPARE_CAPACITY }
        , buff_{std::aligned_alloc(alignof(Object), _capacity)}
    {
        if(!buff_) throw std::bad_alloc();
        if(size) new (buff_) Object[size]{}; // empty braces answer your original query
    }
    

    请记住,向量增长时buff_应该再次aligned_alloc(对于琐碎的类型可以std::realloc() ed),在析构函数中应该std::free() d —和在此之前,应销毁其中的size_对象(显式调用~Object())。

  2. buff_的类型更改为更琐碎但正确对齐的类型:

        using Storage = std::aligned_storage_t<sizeof(Object), alignof(Object)>;
        Storage *buff_;
        Object *data_ = nullptr;
    public:
        explicit myVector(std::size_t size = 0) :
            size_{ size }
            , capacity_{ size + SPARE_CAPACITY }
            , buff_{new Storage(_capacity)}
        {
            if(size) data_ = new (buff_) Object[size]{};
        }
    

    同样,在析构函数中,应该手动销毁对象,但是这次buff_之后可以简单地delete[] d。