他の人はすでに他の問題に対処しているので、ここで1点だけ見ていきます。手動でオブジェクトを削除したいですか?
答えはイエスです。@DavidSchwartzが1つの例を示しましたが、それはかなり珍しいものです。多くのC ++プログラマーがいつも使用しているものの内部にある例を挙げますstd::vector
(そしてstd::deque
、それほど使用されていませんが)。
ほとんどの人が知っているように、std::vector
現在の割り当てが保持できるよりも多くのアイテムを追加すると、/はより大きなメモリブロックを割り当てます。ただし、これを行う場合は、現在ベクターにあるオブジェクトよりも多くのオブジェクトを保持できるメモリブロックがあります。
これを管理するために、内部vector
で行われていることは、オブジェクトを介して生のメモリを割り当てるAllocator
ことです(特に指定しない限り、これはを使用することを意味します::operator new
)。次に、たとえばを使用しpush_back
て項目をに追加するとvector
、内部的にベクターはplacement new
て、(以前は)未使用のメモリ空間の部分に項目を作成します。
さて、あなたerase
がベクターからのアイテムである場合/場合はどうなりますか?それだけで使用することはできませんdelete
-それはそのメモリブロック全体を解放します。他のオブジェクトを破壊したり、それが制御するメモリブロックを解放したりせずに、そのメモリ内の1つのオブジェクトを破壊する必要があります(たとえば、erase
ベクターから5アイテム、すぐにpush_back
5アイテムを追加すると、保証されます)と、ベクターが再割り当てされないれます)あなたがそうするときの記憶。
そのためには、ベクターは、直接、明示的にデストラクタを呼び出すことにより、メモリ内のオブジェクトを破壊しません、を使用するのdelete
。
思いがけず、だれかが大体同じようにvector
(またはstd::deque
実際にそうであるようなその変形)の連続ストレージを使用してコンテナーを作成する場合、ほぼ確実に同じ手法を使用する必要があります。
たとえば、循環リングバッファのコードをどのように記述するかを考えてみましょう。
#ifndef CBUFFER_H_INC
#define CBUFFER_H_INC
template <class T>
class circular_buffer {
T *data;
unsigned read_pos;
unsigned write_pos;
unsigned in_use;
const unsigned capacity;
public:
circular_buffer(unsigned size) :
data((T *)operator new(size * sizeof(T))),
read_pos(0),
write_pos(0),
in_use(0),
capacity(size)
{}
void push(T const &t) {
// ensure there's room in buffer:
if (in_use == capacity)
pop();
// construct copy of object in-place into buffer
new(&data[write_pos++]) T(t);
// keep pointer in bounds.
write_pos %= capacity;
++in_use;
}
// return oldest object in queue:
T front() {
return data[read_pos];
}
// remove oldest object from queue:
void pop() {
// destroy the object:
data[read_pos++].~T();
// keep pointer in bounds.
read_pos %= capacity;
--in_use;
}
~circular_buffer() {
// first destroy any content
while (in_use != 0)
pop();
// then release the buffer.
operator delete(data);
}
};
#endif
標準のコンテナとは異なり、これは直接使用operator new
しoperator delete
ます。実際の使用では、おそらくアロケータクラスを使用する必要がありますが、現時点では、コントリビュートするよりも注意をそらすことが多くなります(IMO、とにかく)。