使用容器中的新位置 我刚刚在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; }; 模板类容器 { 公众: 容器():缓冲区(新的E[100]),大小(0){} ~Container(){delete[]buffer;} void Add(){buffer[size]=E();size++;} void Remove(){size--;缓冲区[size]。~E();} 私人: E*缓冲区; 整数大小; };

使用容器中的新位置 我刚刚在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; }; 模板类容器 { 公众: 容器():缓冲区(新的E[100]),大小(0){} ~Container(){delete[]buffer;} void Add(){buffer[size]=E();size++;} void Remove(){size--;缓冲区[size]。~E();} 私人: E*缓冲区; 整数大小; };,c++,memory-management,placement-new,object-construction,object-destruction,C++,Memory Management,Placement New,Object Construction,Object Destruction,如果未自定义new/delete,则这将在Container()和~Container()中冗余地构造/销毁E对象。这似乎很危险 在Add()中使用placementnew是否是防止危险的冗余构造函数/析构函数调用的最佳方法(除了将类绑定到功能齐全的池之外) 当使用placementnew时,new char[sizeof(E)*100]是否是分配缓冲区的正确方法 这样做将冗余地构造/销毁E对象 看来是这样。newed数组已经应用了默认构造函数,delete[]也将为所有元素调用析构函数。实际上

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

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

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

这样做将冗余地构造/销毁
E
对象

看来是这样。
new
ed数组已经应用了默认构造函数,
delete[]
也将为所有元素调用析构函数。实际上,
Add()
Remove()
方法除了维护
size
计数器外,几乎没有添加其他内容

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

最好选择已经为您处理所有内存问题的

使用placement
new
并自行管理内存需要注意许多问题(包括)

  • 对齐
  • 分配和使用的大小
  • 毁灭
  • 施工问题,如安置
  • 可能的混叠
这些都不是不可能克服的,它已经在标准库中完成了。如果您有兴趣使用自定义分配器,(
void*运算符new(std::size\u t count);
)将是内存分配的适当起点


如果不进一步解释代码的原始用途,那么对于管理容器中的元素,使用
std::vector
std::array
将是更好的选择

这样做将冗余地构造/销毁
E
对象

看来是这样。
new
ed数组已经应用了默认构造函数,
delete[]
也将为所有元素调用析构函数。实际上,
Add()
Remove()
方法除了维护
size
计数器外,几乎没有添加其他内容

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

最好选择已经为您处理所有内存问题的

使用placement
new
并自行管理内存需要注意许多问题(包括)

  • 对齐
  • 分配和使用的大小
  • 毁灭
  • 施工问题,如安置
  • 可能的混叠
这些都不是不可能克服的,它已经在标准库中完成了。如果您有兴趣使用自定义分配器,(
void*运算符new(std::size\u t count);
)将是内存分配的适当起点



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

代码存在许多问题。 如果在调用
Add()
之前调用
Remove()
,则将对已销毁的对象执行赋值

否则,
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;
}
#包括
int计数器=0;
课例{
公众:
示例():ID(++计数器){

这段代码有很多问题。 如果在调用
Add()
之前调用
Remove()
,则将对已销毁的对象执行赋值

否则,
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;
}
#包括
int计数器=0;
课例{
公众:
示例():ID(++计数器){

std::Coutt这段代码有很多错误,但是在这段代码中没有放置-
new
。不,不是。我从来没有说过会。我明白了,我当时误解了这个问题。我想你想在
Remove()中解构
buffer[size-1]
,或在解构之前减量。按照您在示例中的编写方式,您有一个一个一个的错误。@Mindrio:您是对的。由于提取示例而导致的错误。修复了它。此代码有很多错误,但此代码中没有放置-
新的
。不,不是。我从来没有说过会。我明白了,我误解了那么问题来了。我想你应该在
Remove()中解构
buffer[size-1]
,或在解构之前递减。按照您的示例中的编写方式,您有一个off by one错误。@Mindrio:您是对的。由于提取示例而导致的错误。已修复。我不知道
std::allocator
比简单的新位置提供了更强的保证。您能链接到某个引用吗?(cppreference,或standard中的部分)@YamMarcovic。这样做更容易,因为它已经为您完成了所有的艰苦工作。@Silicomancer.No,使用全局分配函数将是正确的
::new(sizeof(E)*100);
@Niall O