【问题标题】:C++ value initialize items of a custom containerC++ 值初始化自定义容器的项
【发布时间】:2018-12-29 07:54:19
【问题描述】:

让我们以自定义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。请给我一些提示。

【问题讨论】:

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


    【解决方案1】:

    就这么简单

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

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

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

    但此选项会初始化所有 _capasity 对象,而不是第一个 _size 对象,如 @bipll 所述。


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

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

    【讨论】:

    • 运行_capasity 初始化,因此要创建一个零元素向量,您需要运行_capasity 构造函数。
    • @bipll 没错,我错过了。
    【解决方案2】:

    调用时注意

            _buff = new Object[_capasity];
    

    (顺便说一句,你为什么把这个初始化从初始化列表中移到构造函数体中?)你已经有了默认初始化的_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_alloced(对于普通类型可以是 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。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-05-20
      • 1970-01-01
      • 1970-01-01
      • 2017-07-21
      • 2011-08-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多