1

我刚刚在 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()newdelete

new是否以最佳方式使用放置Add()来防止危险的冗余构造函数/析构函数调用(除了将类绑定到功能齐全的池)?

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

4

2 回答 2

3

EAFAIK 这将冗余地构造/破坏对象

看起来是这样。newed 数组已经应用了默认构造函数,并且会delete[]为所有元素调用析构函数。实际上,Add()andRemove()方法除了维护size计数器之外几乎没有什么作用。

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

最好的办法是选择std::allocator已经为您处理所有内存问题的。

使用布局new和自己管理内存需要您了解许多问题(包括);

  • 结盟
  • 分配和使用的大小
  • 破坏
  • 就位等施工问题
  • 可能的混叠

这些都不是不可能克服的,它已经在标准库中完成了。如果您对自定义分配器感兴趣,全局分配函数( void* operator new (std::size_t count);) 将是内存分配的合适起点。


如果不进一步解释代码的原始用途 - astd::vector或 astd::array将是管理容器中元素的更好选择。

于 2016-02-01T11:39:03.313 回答
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;
}
于 2016-02-01T12:08:24.653 回答