I am getting all kinds of memory errors when testing the code in the header file. Please help me by letting me know what's wrong in the same. Thank you!
The code in question is the one in the code block below. It has comments so its pretty self explanatory.
Thank you very much for your help!!!
#include <algorithm>
class sorted_sc_array {
public:
sorted_sc_array() : size_(0), ptr_(nullptr), arr_len(1000) {
ptr_ = new signed char[arr_len];
}
~sorted_sc_array() { delete[] ptr_; }
// IMPLEMENT ME (DONE!!!! SOME EDITS REQD)
sorted_sc_array(const sorted_sc_array& A) {this->size_ = A.size_; this->ptr_ = A.ptr_; /* change this to match the definition of operator=() function */}
// IMPLEMENT ME (DONE!!!!)
sorted_sc_array& operator=(const sorted_sc_array& A) {
if (this == &A) return *this;
delete[] ptr_;
size_ = A.size_;
if (size_ == 0) ptr_ = nullptr;
else {
ptr_ = new signed char[size_];
std::copy(A.ptr_, A.ptr_ + size_, ptr_);
}
return *this;
}
// RETURNS SIZE OF THE ARRAY (i.e. HOW MANY ELEMENTS IT STORES)
int size() const { return size_; }
// RETURNS RAW POINTER TO THE ACTUAL DATA, CAN BE INVOKED AT ANY TIME
const signed char* data() const { return ptr_; }
// IMPLEMENT ME: AFTER INSERT COMPLETES THE ARRAY MUST BE IN ASCENDING ORDER (TBD!!!)
void insert(signed char c) {
if (size_ < arr_len) {
ptr_[size_++] = c;
std::sort(ptr_, ptr_ + size_);
}
else {
int arr_len_new = arr_len*2;
ptr_ = new signed char[arr_len_new];
std::copy(ptr_, ptr_ + size_, ptr_);
ptr_[size_++] = c;
std::sort(ptr_, ptr_ + size_);
}
// maybe use std::sort (myvector.begin(), myvector.end());
// if inefficient, use binary insertion
}
private:
int size_; // size of the array
signed char* ptr_; // pointer to the array
unsigned int arr_len; // dynamic mem alloc for array
}; // class sorted_sc_array
The insert() function has a number of errors when it's growing the array.
It doesn't update arr_len with the new length.
It's reassigning ptr_ with the new array before it has copied the values from the old array, and then it's copying the array to itself. You need to use a temporary variable for this.
It never frees the old array.
This fixes those problems:
void insert(signed char c) {
if (size_ < arr_len) {
ptr_[size_++] = c;
std::sort(ptr_, ptr_ + size_);
}
else {
arr_len = arr_len*2;
signed char *ptr_new = new signed char[arr_len];
std::copy(ptr_, ptr_ + size_, ptr_new);
delete[] ptr_;
ptr_ = ptr_new;
ptr_[size_++] = c;
std::sort(ptr_, ptr_ + size_);
}
You don't specify, what concrete errors you get. Although, most likely your problems come from ignoring the arr_len member. You copy size_ and allocate memory properly, but you ignore arr_len when initializing or copying. This produces problems later on, when you access and compare the uninitialized arr_len.
Related
Condition
In lectures, we have already started to implement our vector. In this task, you need to develop it: add the Size, Capacity, and PushBack methods. Send the simple_vector.h header file containing the SimpleVector class template declaration and definition for verification:
Requirements:
the Capacity method should return the current capacity of the vector — the number of elements that fit into the memory block currently allocated by the vector
the Size method must return the number of elements in the vector
the PushBack method adds a new element to the end of the vector; if there is no free space left in the current allocated memory block (i.e. Size() == Capacity()), the vector must allocate a block of size 2 * Capacity(), copy all the elements to it, and delete the old one.
the first call to the PushBack method for a newly created object must make the capacity equal to one
the Push Back method must have a amortized constant complexity
the begin and end methods must return iterators the current beginning and end of the vector
the current memory block allocated by the vector must be freed in the destructor
also see the attached solution template for additional requirements for working with SimpleVector in unit tests.
The preparation of the decision:
simple_vector.h: https://d3c33hcgiwev3.cloudfront.net/q-OL4qX_EeilzRLZf2WxfA_ac4e8270a5ff11e89fd0455a8819d387_simple_vector.h?Expires=1596067200&Signature=cLfBpytTripoqpOYaW9g4~2-JqTI~8HtxahNwNATwBeq28RdXCvkcqghN~UUPv~wx1XZTVOTs8JDsZQjEALk6Soy70QFADkK9lSfFpLNcQq-Dxd4oxk-C5QDEhadM1LrVGe8Rmz0jRYgIV5sDTvAATBhiY3k-KqbAaDe1AK6QiE_&Key-Pair-Id=APKAJLTNE6QMUY6HBC5A
simple_vector.cpp: https://d3c33hcgiwev3.cloudfront.net/uoPvEoauEeianAr0yIdmDg_bae6cec086ae11e88d9327752d64e780_simple_vector.cpp?Expires=1596067200&Signature=CE1Mox1yU6LjGDXL1xstxT9anv9NI~otNwhBw5AbPyLBquRIi9E6cotR~BQsrvU-djoksfjV9YgnsyF00eFnVjsk~oF0z18wkVkgdIirPB-NNLH0aFvD4WFG97qmSuD0WjeetWyi6UR5BKYCnwfO~ax6-HZLM-GWheO9LHc~BvE_&Key-Pair-Id=APKAJLTNE6QMUY6HBC5A
Comment:
The header file that you send for verification should not include the <vector>, <list>, <forward_list>, <deque>, <map> files. If you have one of these files enabled, you will get a compilation error.
Hint:
For sure, your implementation of the SimpleVector class template will have a field that is a pointer. In the default constructor, you will need to initialize it with something. In the lectures, we only discussed one way to initialize pointers — using the new operator. In C++, there is a special value that means a pointer that points to nothing — nullptr:
int* p = nullptr;
string* q = nullptr;
map<string, vector<int>>* r = nullptr;
You can use nullptr to initialize the pointer in the default constructor.
How to send:
When the work is ready, you can upload files for each part of the task on the 'My work'tab.
And here is my .hsolution to which the Coursera testing system responds a 10 != 8: Memory leak detected. However I can't figure out where the leak is going. Help me pls.
#pragma once
#include <cstdlib>
using namespace std;
template <typename T>
class SimpleVector {
public:
SimpleVector()
: data(nullptr)
, end_(data)
, size_(0) {}
explicit SimpleVector(size_t size)
: data(new T[size])
, end_(data + size)
, size_(size) {}
~SimpleVector() {
delete[] data;
}
T& operator[](size_t index) { return data[index]; }
T* begin() const { return data; }
T* end() const { return end_; }
size_t Capacity() const { return end_ - data; }
size_t Size() const { return size_; }
void PushBack(const T& value) {
if (size_ == Capacity()) {
if (size_ == 0) {
delete[] data;
data = new T[1];
data[size_] = value;
++size_;
end_ = data + size_;
}
else {
T* local_data = new T[size_];
for (size_t i = 0; i < size_; ++i) {
local_data[i] = data[i];
}
delete[] data;
data = new T[2 * Capacity()];
for (size_t i =0; i < size_; ++i) {
data[i] = local_data[i];
}
delete[] local_data;
data[size_] = value;
++size_;
end_ = data + size_ * 2;
}
}
else {
data[size_] = value;
size_++;
}
}
private:
T *data;
T *end_;
size_t size_;
};
Thank you in advance.
There is a memory leak in PushBack due to lack of exception safety. Consider:
T* local_data = new T[size_];
// potentially throwing operations here...
delete[] local_data;
If those operations throw, then delete[] local_data; will never be executed.
Typical way to avoid such memory leak is to use smart pointers instead of bare pointers for ownership. The antiquated way is to use try-catch.
Your class also fails to enforce the class invariant of uniqueness of data pointer. Such constraint is essential for the destructor to be correct, because an allocation must be deleted exactly once, and no more.
Making a copy of an instance of the class will result in undefined behaviour because of same pointer being deleted in multiple destructors. Another consequence is that the assigment operators will leak the previously allocated memory (before the UB occurs in the destructor):
{
SimpleVector vec(42);
SimpleVector another(1337);
SimpleVector vec = another; // memory leak in assignment operator
} // undefined behaviour in the destructor
The problem is in the copy and move constructors and assignment operators, which you've left as implicitly generated. The implicitly generated special member functions will copy the pointer value, violating its uniqueness (and failing to delete the previous allocation in case of assignment). In other words, those functions perform a shallow copy.
Using a smart pointer as the member is an easy solution. Otherwise, you must implement copy and move constructors and assignment operators that don't leak, nor violate uniqueness.
Note that even if you did use a smart pointer, you'd still need user defined copy etc. because of the end pointer. If you instead used an integer that is relative to data, then you could avoid defining those functions.
P.S. There is no need to allocate twice, and copy twice. Instead, allocate one larger buffer, copy the old one, delete the old, point to the new.
P.P.S. As a sidenote: The vector you are implementing behaves quite differently from the standard vector, which is probably intentional by your teacher. When I add an object to a vector of 10 elements, I would expect only one element to be created and possibly 10 be copied due to relocation, rather than 20 objects being created with 9 being unaccessible.
A proper implementation of vector separates the allocation of memory, and creation of objects into that memory which allows the growth of the memory to be geometric without creating objects until they are added into the vector. I suspect that how to do this is outside the scope of your exercise.
I wouldn't call it a leak, but you treat end_ inconsistently. It seems like you are treating Size and Capacity as equivalent values, they are not.
Either end_ should point one past the allocated (but not necessarily populated) memory, and you return data + size in end(), or it should point one past the last element, and you should store size_t capacity_ not size_t size_;
Here is solution without memory leak. Thank you.
#pragma once
#include <cstdlib>
using namespace std;
template <typename T>
class SimpleVector {
public:
SimpleVector() {
data_ = nullptr;
end_ = data_;
size_ = 0;
capacity_ = 0;
}
explicit SimpleVector(size_t size) {
data_ = new T[size];
end_ = data_ + size;
size_ = size;
capacity_ = size;
}
SimpleVector(const SimpleVector& that)
: data_(that.data_)
, end_(that.end_)
, size_(that.size_)
, capacity_(that.capacity_) {}
SimpleVector& operator = (const SimpleVector& that) {
data_ = that.data_;
end_ = that.end_;
size_ = that.size_;
capacity_ = that.capacity_;
}
~SimpleVector() { delete[] data_; }
T& operator[](size_t index) {
return data_[index];
}
T* begin() const { return data_; }
T* end() const { return data_ + size_; }
size_t Capacity() const { return capacity_; }
size_t Size() const { return size_; }
void PushBack(const T& value) {
if (size_ == capacity_) {
if (capacity_ == 0) { // т. е. создали конструктором по умолчанию, size_ = 0
data_ = new T[1];
capacity_ = 1;
data_[size_] = value;
++size_;
end_ = data_ + size_;
}
else if (capacity_ == size_) { // т. е. capacity_ == size_
T* local_data = new T[2 * size_];
for (size_t i = 0; i < size_; ++i) {
local_data[i] = data_[i];
}
delete[] data_;
data_ = new T[2 * size_];
for (size_t i = 0; i < size_; ++i) {
data_[i] = local_data[i];
}
delete[] local_data;
data_[size_] = value;
size_++;
capacity_ *= 2;
end_ = data_ + size_;
}
}
else {
data_[size_] = value;
size_++;
}
}
private:
T *data_;
T *end_;
size_t size_;
size_t capacity_;
};
The following code constitutes a MCVE, this reproduces the problem I want to ask about but it's not the real code. The real code is quite more complicated so that's why I wrote this for a demonstration of the problem.
The key feature I am looking for is to be able to grow a dynamically allocated array, please do not suggest using the stl because it's explicitly forbidden. This code is for educational purpose and thus there are restrictions.
#include <cstring>
#include <iostream>
class Value
{
public:
Value(int value = 0);
Value(const Value &value);
Value &operator =(const Value &other);
~Value();
operator int() {return *m_absurdPointer;}
private:
int *m_absurdPointer;
};
Value::Value(int value) :
m_absurdPointer(new int[1])
{
*m_absurdPointer = value;
}
Value::Value(const Value &value)
{
m_absurdPointer = new int[1];
memcpy(m_absurdPointer, value.m_absurdPointer, sizeof(*m_absurdPointer));
}
Value &Value::operator =(const Value &other)
{
m_absurdPointer = new int[1];
memcpy(m_absurdPointer, other.m_absurdPointer, sizeof(*m_absurdPointer));
return *this;
}
Value::~Value()
{
delete[] m_absurdPointer;
}
class ValueArray
{
public:
ValueArray();
~ValueArray();
void append(const Value &value);
void show() const;
private:
Value *m_array;
unsigned int m_capacity;
unsigned int m_length;
};
ValueArray::ValueArray() :
m_array(nullptr)
, m_capacity(0)
, m_length(0)
{
}
ValueArray::~ValueArray()
{
delete[] m_array;
}
void
ValueArray::append(const Value &value)
{
if (m_length >= m_capacity)
{
Value *newarray;
unsigned int unitSize;
unitSize = 1;
newarray = new Value[m_capacity + unitSize];
if ((m_capacity > 0) && (m_array != nullptr))
memcpy(newarray, m_array, m_capacity * sizeof(*m_array));
delete[] m_array;
m_array = newarray;
m_capacity += unitSize;
}
m_array[m_length++] = value;
}
void
ValueArray::show() const
{
for (size_t i = 0 ; i < m_length ; ++i)
std::cout << static_cast<int>(m_array[i]) << std::endl;
}
int
main(void)
{
ValueArray example;
for (int i = 0 ; i < 10 ; ++i)
example.append(Value(i));
example.show();
return 0;
}
It causes as you can see a double free issue, because the delete[] m_array; calls the destructor of the class Value after it has copied the values to the re-newed array.
I tried to do this with malloc()/realloc() but I need the destructor of Value() to be called so new is mandatory because I can't use free().
How to prevent this?, if I remove the delete[] m_absurdPointer; the double free would be gone of course but there would be a memory leak.
You basically want to implement an own vector class, right?
OK, first things first: As far as I know you cannot grow previously allocated memory. At least not with the standard allocator.
So you need to allocate a new, larger chunk of memory.
You can do this the standard way, using new:
Type * newdata = new Type[size];
In this case the constructor of the class Type will be called for each new element, which is size times.
To get your old data into that new array you need to copy or move it there:
for (size_t it = 0; it < oldsize; ++it) {
newdata[it] = olddata[it];
// newdata[it] = std::move(olddata[it]);
}
This is what std::copy resp. std::move are doing. (You could also use std::swap inside a loop.)
For that to work the Type class needs both a default constructor and a valid implementation of copy or move assignment.
You're using memcpy. In C++, this is generally a bad idea: Your implemented assignment operator isn't called, Therefore both the objects in your old array and the raw copies are using the same pointer, which is why you get that double free, obviously.
You could also allocate raw memory and use placement new to copy or move construct the new objects from the old ones:
void * memory = new char[size * sizeof(Type)];
for (size_t it = 0; it < oldsize; ++it) {
new (memory + it * sizeof(Type)) Type(olddata[it]); // copy
}
The above is only an example, for real code you need to consider alignment, too.
Finally, I'm sure you can somehow trick the default allocator to free your (old) memory without destructing the objects within, this allowing you to use the raw copy memcpy made. Though this would be a hack and could break on complex classes, it's not the C++ way of doing this.
The idiomatic way is to copy or move the old objects to the new storage (with either assignment or construction).
You should use the move-constructor if you have to stick with an vector-like implementation of ValueArray:
class Value
{
public:
Value(int value = 0);
Value(const Value &value);
Value(Value&& val);
Value &operator =(const Value &other);
Value &operator =(Value&& other);
~Value();
operator int() {return *m_absurdPointer;}
private:
int *m_absurdPointer;
};
Value::Value(Value&& o) : m_absurdPointer(o.m_absurdPointer) {
o.m_absurdPointer = nullptr;
}
Value &operator =(Value&& o) {
delete[] this->m_absurdPointer;
this->m_absurdPointer = o.m_absurdPointer;
o.m_absurdPointer = nullptr;
}
void
ValueArray::append(const Value &value)
{
if (m_length >= m_capacity)
{
Value *newarray;
unsigned int unitSize;
unitSize = 1;
newarray = new Value[m_capacity + unitSize];
if ((m_capacity > 0) && (m_array != nullptr)) {
std::move(m_array, m_array + m_length, newarray);
}
delete[] m_array;
m_array = newarray;
m_capacity += unitSize;
}
}
I am writing a operator function for - where my class object is a dynamic array of integer.
the operator takes lhs and rhs object and return an object which is the set of elements in lhs but not in rhs.
though I have written the function but I am not able to return the set since the destructor is called right after the object is returned.
IntegerSet & IntegerSet::operator - (IntegerSet & rhs) const
{
IntegerSet temp(capacity);//local object created to store the elements same size as lhs
int k=0;
int lhssize = ElementSize();//no. of elements in the set
int rhssize = rhs.ElementSize();
for (int i=0;i<lhssize;i++)
{
for (int j=0;j<rhssize;j++)
{
if (rhs.ptr[j]!=ptr[i])
{
k++;
}
}
if(k==rhssize)
{
temp = temp + ptr[i];
}
k=0;
}
return temp;
}
and here is the constructor if you cannot understand the object
IntegerSet::IntegerSet(const int & size)//works correctly
{
capacity = size;
ptr = new int [capacity]();
}
IntegerSet::IntegerSet(const int & size)//works correctly
{
capacity = size;
ptr = new int [capacity]();
}
IntegerSet::IntegerSet(const IntegerSet & copy) : capacity(copy.capacity)//works correctly
{
ptr = copy.clonemaker();
}
IntegerSet::~IntegerSet()
{
capacity = 0;
delete [] ptr;
}
int * IntegerSet::clonemaker() const // works correctly
{
if(ptr==NULL)
{
return NULL;
}
int *tempptr = new int [capacity];
for(int i=0;i<capacity;i++)
{
tempptr[i]=ptr[i];
}
return tempptr;
}
You'll have to return by value. The local object will be destroyed when the function returns, and there's no way to prevent that.
For that to work, your class will have to correctly follow the Rule of Three to make sure it's correctly copyable. In C++11 or later, you might also consider making it movable, to avoid unnecessary memory allocation and copying (although, in this case, the copy should be elided anyway).
Better still, follow the Rule of Zero and store a vector<int>, which will do all this for you, rather than trying to juggle raw pointers.
You need to change to return the result by value.
IntegerSet IntegerSet::operator - (IntegerSet & rhs) const
Also it would make more sense to supply rhs by const reference when taking a second look.
Given the following push_back code:
template <typename T>
void Vector<T>::push_back(const T& item) {
if (_size == _capacity) {
_capacity = _capacity + (_capacity > 1 ? (_capacity / 2) : 1);
T* newVec = new T[_capacity];
memcpy(newVec, _ptr, _size*(sizeof(T)));
delete [] _ptr;
_ptr = newVec;
}
_ptr[_size++] = item;
}
While the vector's class contain these members:
T* _ptr;
size_t _size;
size_t _capacity;
Is that implementation safe..? Will memcpy do his job correctly even if T is polymorphic type?
Would love to hear some suggestions about how to improve the implementation.
Don't use std::memcpy
You may only use std::memcpy on trivially copyable objects. Otherwise it's undefined behaviour.
You can, however, just copy all elements by hand. std::copy is suitable, as it may be specialized for trivial types:
In practice, implementations of std::copy avoid multiple assignments and use bulk copy functions such as std::memcpy if the value type is TriviallyCopyable
template <typename T>
void Vector<T>::push_back(const T& item) {
if (_size == _capacity) {
size_t new_cap = _capacity > 0 ? 2 * _capacity : 2;
T * newVec = new T[new_cap];
std::copy(_ptr, _ptr + _size, newVec);
std::swap(_capacity, new_cap);
std::swap(_ptr, newVec);
delete[] newVec;
}
_ptr[_size++] = item;
}
Note that your original implementation divided the capacity if the vector was too small.
More improvements
If you use std::allocator (or a compatible class), things get a little bit easier. You would use .allocate to get memory, .construct(pointer, value) to actually construct objects, .destroy to call their destructors and .deallocate to remove memory previously created with .allocate. Thus you don't need a default constructible object if you just want to use .push_back().
The following code is a quick minimal sketch. Note that there are some problems, for example reserve() isn't exception safe, as the allocated memory in tmp needs to be cleaned up if a constructor throws.
template <typename T, class Allocator = std::allocator<T> >
class Vector{
public:
typedef typename Allocator::pointer pointer;
typedef typename Allocator::size_type size_type;
Vector() : _ptr(0), _capacity(0), _size(0){}
~Vector() {
if(_capacity == 0)
return;
while(_size > 0)
pop_back();
_alloc.deallocate(_ptr, _capacity);
}
void reserve(size_type new_cap){
if(new_cap <= _capacity)
return;
// allocate memory
T * tmp = _alloc.allocate(new_cap);
// construct objects
for(unsigned int i = 0; i < _size; ++i){
_alloc.construct(tmp + i, _ptr[i]); // or std::move(_ptr[i])
}
// finished construction, save to delete old values
for(unsigned int i = 0; i < _size; ++i){
_alloc.destroy(_ptr + i);
}
// deallocate old memory
_alloc.deallocate(_ptr, _capacity);
_ptr = tmp;
_capacity = new_cap;
}
void push_back(const T& val){
if(_size == _capacity)
reserve(_capacity > 0 ? 2 * _capacity : 1);
_alloc.construct(_ptr + _size, val);
_size++; // since T::T(..) might throw
}
void pop_back(){
_alloc.destroy(_ptr + _size - 1);
_size--;
}
T& operator[](size_type index){
return _ptr[index];
}
private:
pointer _ptr;
size_type _capacity;
size_type _size;
Allocator _alloc;
};
This is not safe, for example if T is doing this:
struct T
{
T* myself;
T() : myself(this) {}
void foo() { myself->bar(); }
void bar() { ... }
};
Since you moved the memory location of the object by simply moving it's memory without calling constructors/destructors, myself will not be updated and when you call foo afterward, it will call bar with an invalid this pointer.
Imagine what would happen if T was itself a vector.
Now you have two vectors pointing to the same buffer, and they will both delete the buffer... bad idea.
(Well, technically it's undefined behavior the moment you memcpy. I just gave you the most likely result.)
It's not safe in general - but C++11 provides std::is_trivially_copyable :
#include <type_traits>
...
if (std::is_trivially_copyable<T>::value)
// *can* use memcpy...
I'm trying to write a function that will change the size of a dynamic array to a new size. In my header file, I have:
Image **images; //pointer to a dynamic array of image pointers
int maximum; //size
I want to do this by allocating a new array and copying the values over without changing their indices. If there are non-null pointers outside the range newmax, then we cant do this. So heres what I have:
There are no compilation or runtime errors. However, I find that the new array isnt getting sized right. When I run the following test case:
I should get an index out of bounds error, but instead the system lets it slide. Can anyone see the mistake? I've looked for hours but cant find anything.
images=newArray;
for (int i =0;i<newmax;i++)
*images[i]=*newArray[i];
This is odd. images and newArray are now the same, hence no need to copy the contents of newArray back to itself. So remove this loop? Also, need to add:
maximum = newmax;
If the '1' is the index, this should cause
firstScene->addpicture("red10.bmp", 1, 13, 72);
to give an out of bounds error, whereas at the moment it might seg fault?
You should extract this functionality to a separate class and have a data member in Scene of that type:
struct ImagePtrVector {
typedef Image *value_type;
typedef int size_type;
ImagePtrVector() : _begin (), _end (), _end_alloc () {}
~ImagePtrVector() {
for (value_type x = _begin; x != _end; ++x) {
delete *x;
}
delete[] _begin;
}
// Either define these two yourself or mark private:
ImagePtrVector(ImagePtrVector const &x);
ImagePtrVector& operator=(ImagePtrVector const &x);
value_type& operator[](size_type index) {
assert(0 <= index); // Or other checking as you like.
assert(index < size());
return _begin[index];
}
value_type const& operator[](size_type index) const {
assert(0 <= index); // Or other checking as you like.
assert(index < size());
return _begin[index];
}
size_type size() const { return _end - _begin; }
size_type capacity() const { return _end_alloc - _begin; }
void reserve(size_type capacity) {
if (this->capacity() < capacity) {
value_type *new_begin = new value_type[capacity];
// Exception-safe only because I know the below won't throw.
std::copy(_begin, _end, new_begin);
_end_alloc = new_begin + capacity;
_end = new_begin + this->size();
delete[] _begin;
_begin = new_begin;
}
}
void resize(size_type size) {
reserve(size);
for (size_type diff = size - this->size(); diff > 0; --diff) {
*_end++ = new Image();
}
}
// Add push_back, begin/end, etc. to taste.
private:
value_type *_begin, *_end, *_end_alloc;
};
The differences from std::vector and boost::ptr_vector are not coincidence, and you should evaluate whether you really need to write a special container or can reuse an existing generic container.