在容器中使用placement new

时间:2016-02-01 11:33:26

标签: c++ memory-management placement-new object-construction object-destruction

我刚刚在C ++中遇到了一些容器实现。该类使用内部缓冲区来管理其对象。这是一个没有安全检查的简化版本

template <typename E> class Container
{
public:
   Container() : buffer(new E[100]), size(0) {}
   ~Container() { delete [] buffer; }

   void Add() { buffer[size] = E(); size++; }
   void Remove() { size--; buffer[size].~E(); }

private:
   E* buffer;
   int size;
};

AFAIK如果E / Container()未自定义,这将在~Container()new中冗余地构建/销毁delete个对象。这似乎很危险。

new中使用展示位置Add()是防止危险的冗余构造函数/析构函数调用的最佳方法(除了将类绑定到功能齐全的池之外)?

使用展示位置new时,new char[sizeof(E)*100]是否是分配缓冲区的正确方法?

2 个答案:

答案 0 :(得分:3)

  

AFAIK这将冗余地构造/破坏E个对象

看起来如此。 new ed数组已经应用了默认构造函数,delete[]也会为所有元素调用析构函数。实际上,除了维护Add()计数器之外,Remove()size方法几乎不会增加。

  

使用placement new时,new char[sizeof(E)*100]是否是分配缓冲区的正确方法?

最好的选择是为您处理所有内存问题的std::allocator

使用展示位置new并自行管理内存需要您了解一些问题(包括);

  • 对齐
  • 已分配和使用的尺寸
  • 销毁
  • 施工问题,例如安置
  • 可能的别名

这些都不可能克服,它刚刚在标准库中完成。如果您对追求自定义分配器感兴趣,global allocation functionsvoid* operator new (std::size_t count);)将是内存分配的合适起点。

如果不对代码的原始目的进行进一步说明,std::vectorstd::array将是管理容器中元素的更好选择。

答案 1 :(得分:1)

代码存在许多问题。 如果您在致电Remove()之前致电Add(),则会将分配给一个被破坏的对象。

否则delete[] buffer将调用数组中100个对象的析构函数。以前可能已经打过电话。

这是一个有效的计划:

#include <iostream>

int counter=0;

class Example {

    public:
        Example():ID(++counter){
           std::cout<<"constructing "<<ID<<std::endl;
        }
        ~Example(){
            std::cout<<"destructing "<<ID<<std::endl;
            ID=-1;
        }
    private:


      int ID;
};

template <typename E> class Container
{
public:
   Container() : buffer(new char [100*sizeof(E)]), size(0) {}
   ~Container() {
        for(size_t i=0;i<size;++i){
            reinterpret_cast<E*>(buffer)[i].~E();
        }
        delete []  buffer; 
    }

   void Add() { new (buffer+sizeof(E)*size) E(); size++; }
   void Remove() { reinterpret_cast<E*>(buffer)[--size].~E(); }

private:
   void* buffer;
   size_t size;
};


int main() {
    Container<Example> empty;

    Container<Example> single;
    Container<Example> more;

    single.Add();

    more.Add();

    more.Remove();

    more.Add();
    more.Add();
    more.Remove();

    return 0;
}