在容器中使用 placement new
Using placement new in a container
我刚刚发现了一些用 C++ 实现的容器。 class 使用内部缓冲区来管理其对象。这是一个没有安全检查的简化版本:
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 如果 new
/delete
未自定义,这将 construct/destruct E
在 Container()
和 ~Container()
中冗余对象。这似乎很危险。
在 Add()
中使用放置 new
是否是防止危险的冗余构造函数/析构函数调用的最佳方法(除了将 class 绑定到功能齐全的池之外)?
使用放置 new
时,new char[sizeof(E)*100]
是否是分配缓冲区的正确方法?
AFAIK this will construct/destruct E
objects redundantly
看起来是这样。 new
ed 数组已经应用了默认构造函数,delete[]
也会为所有元素调用析构函数。实际上,Add()
和 Remove()
方法除了维护 size
计数器外几乎没有添加。
When using placement new, would new char[sizeof(E)*100]
be the correct way for allocating the buffer?
最好选择已经为您处理所有内存问题的 std::allocator
。
使用放置 new
并自行管理内存需要您了解许多问题(包括);
- 对齐
- 分配和使用的大小
- 毁灭
- 安置等施工问题
- 可能存在别名
None这些是不可能超越的,标准库中已经做到了。如果您有兴趣使用自定义分配器,global allocation functions (void* operator new (std::size_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;
}
我刚刚发现了一些用 C++ 实现的容器。 class 使用内部缓冲区来管理其对象。这是一个没有安全检查的简化版本:
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 如果 new
/delete
未自定义,这将 construct/destruct E
在 Container()
和 ~Container()
中冗余对象。这似乎很危险。
在 Add()
中使用放置 new
是否是防止危险的冗余构造函数/析构函数调用的最佳方法(除了将 class 绑定到功能齐全的池之外)?
使用放置 new
时,new char[sizeof(E)*100]
是否是分配缓冲区的正确方法?
AFAIK this will construct/destruct
E
objects redundantly
看起来是这样。 new
ed 数组已经应用了默认构造函数,delete[]
也会为所有元素调用析构函数。实际上,Add()
和 Remove()
方法除了维护 size
计数器外几乎没有添加。
When using placement new, would
new char[sizeof(E)*100]
be the correct way for allocating the buffer?
最好选择已经为您处理所有内存问题的 std::allocator
。
使用放置 new
并自行管理内存需要您了解许多问题(包括);
- 对齐
- 分配和使用的大小
- 毁灭
- 安置等施工问题
- 可能存在别名
None这些是不可能超越的,标准库中已经做到了。如果您有兴趣使用自定义分配器,global allocation functions (void* operator new (std::size_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;
}