I'm trying to make my own vector in C++ so I could understand more how it works !
This is the code:
#pragma once
template<typename T>
class Vector {
public:
Vector() {
// allocate 2 elements
ReAlloc(2);
}
void pushBack(const T& value) {
if (m_Size >= m_Capacity) {
ReAlloc(m_Capacity / 2);
}
m_Data[m_Size++] = value;
}
const T& operator[](size_t index) const {
/*
if (index >= m_Size) {
// assert
}
*/
return m_Data[index];
}
T& operator[](size_t index) {
/*
if (index >= m_Size) {
// assert
}
*/
return m_Data[index];
}
const size_t Size() const { return m_Size; }
size_t Size() { return m_Size; }
private:
T* m_Data = nullptr;
size_t m_Size = 0;
size_t m_Capacity = 0;
private:
void ReAlloc(size_t newCapacity) {
// 1. allocate a new block of memory
// 2. copy/move old elements into the new block
// 3. delete the old one
T* newBlock = new T[newCapacity];
if (newCapacity < m_Size) {
m_Size = newCapacity;
}
for (size_t i = 0; i < m_Size; i++) {
newBlock[i] = m_Data[i];
}
delete[] m_Data;
m_Data = newBlock;
m_Capacity = newCapacity;
}
};
However, When I try to use it from main.cpp like this:
#include <iostream>
#include <string>
#include "Vector.h"
#define print(x) std::cout << x
#define println(x) std::cout << x << std::endl
template<typename T>
void PrintVector(Vector<T>& vector) {
for (size_t i = 0; i < vector.Size(); i++) {
println(vector[i]);
}
println("------------------------------------------");
}
int main() {
Vector<std::string> vector;
vector.pushBack("Ahmed");
vector.pushBack("C++");
vector.pushBack("Vector");
PrintVector(vector);
}
The code give me this output:
Ahmed
Vector
------------------------------------------
(process 7540) exited with code -1073740940.
it's not even printing C++ and the code acts weird, whenever I try o change anything the output became more mess, Could anyone tell me what did I do wrong please ?!.
Thx ! :)
In your pushBack function, when the size is greater than or equal to capacity, you are doing:
ReAlloc(m_Capacity / 2);
which doesn't make sense. If you need additional space to add elements, you should increase the capacity of the underlying array, not decrease it by half.
You are probably looking for:
ReAlloc(m_Capacity * 2);
which doubles the underlying capacity.
Here's a working demo, without any segfault.
Related
CheckedArray::CheckedArray(int size) :mSize(size){
int *mArray = new int[size];
for(int i = 0; i < size; i++)
mArray[i] = 0;
}
CheckedArray::~CheckedArray() {
if (mArray == NULL){
return;
}
else {
delete[] mArray;
}
}
I'm using dynamic memory allocation to create a new array. I want to check if the pointer is null, then return. If not, then delete. I'm getting these error messages, but I have no idea what's wrong.
(9094,0x100094600) malloc: *** error for object 0x10001e7b3: pointer being freed was not allocated
(9094,0x100094600) malloc: *** set a breakpoint in malloc_error_break to debug
To be completely clear
CheckedArray::CheckedArray(int size) :mSize(size){
int *mArray = new int[size];
for(int i = 0; i < size; i++)
mArray[i] = 0;
}
should be
CheckedArray::CheckedArray(int size) :mSize(size), mArray(new int[size]){
for(int i = 0; i < size; i++)
mArray[i] = 0;
}
Your version creates a local variable mArray which shadows the class variable of the same name.
Here is an example of what std::unique_ptr can do for you :
#include <iostream>
#include <algorithm>
#include <memory>
// https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#r11-avoid-calling-new-and-delete-explicitly
// so use https://en.cppreference.com/w/cpp/memory/unique_ptr/make_unique
// prefer range based for loops, they can't go out of bounds : https://en.cppreference.com/w/cpp/language/range-for
class dynamic_int_array_t final
{
public:
// creates an "empty array" with enough memory for 4 ints.
dynamic_int_array_t() :
m_capacity{ 4ul }, // start with a capacity for 4 ints.
m_size{ 0ul }, // but actually none are stored yet
m_values{ std::make_unique<int[]>(m_capacity) }
{
}
// allows you to construct an array from a list of integers
dynamic_int_array_t(std::initializer_list<int>&& values) :
m_capacity{ values.size() },
m_size{ values.size() },
m_values{ std::make_unique<int[]>(m_capacity) }
{
std::copy(values.begin(), values.end(), m_values.get());
}
~dynamic_int_array_t() = default; // destructor will destruct unique_ptr and free memory
// non-copyable non-movable (simplifies things for now)
dynamic_int_array_t(const dynamic_int_array_t&) = delete;
dynamic_int_array_t& operator=(const dynamic_int_array_t&) = delete;
dynamic_int_array_t(dynamic_int_array_t&&) = delete;
dynamic_int_array_t& operator=(dynamic_int_array_t&&) = delete;
// begin and end allow range based for loops to work
// range based for loops don't allow you to go out of bounds.
auto begin() const
{
return m_values.get();
}
// end should point "one past" the array (that's how end works)
auto end() const
{
int* ptr = begin();
ptr += m_size;
return ptr;
}
std::size_t size() const
{
return m_size;
}
void add(const int value)
{
// if not enough memory then allocate more
if (m_size == m_capacity) grow_capacity();
// add new value at the end
m_values[m_size] = value;
m_size++;
}
// add another array to this one
void append(const dynamic_int_array_t& rhs)
{
for (int value : rhs)
{
add(value);
}
}
private:
void grow_capacity()
{
m_capacity *= 2;
// allocate new memory
auto tmp = std::make_unique<int[]>(m_capacity);
// copy content to new memory
std::copy(begin(), end(), tmp.get());
// swap new memory with tmp so m_values will now be the newly allocated memory and tmp will hold the previously allocated memory
std::swap(tmp, m_values);
// tmp will go out of scope and delete old buffer
}
std::size_t m_capacity;
std::size_t m_size;
std::unique_ptr<int[]> m_values;
};
int main()
{
dynamic_int_array_t array{ 4,5 };
for (int n = 10; n < 20; ++n)
{
array.add(n);
}
for (const int value : array)
{
std::cout << value << " ";
}
return 0;
}
My string-dynamic-array.cpp file
#include <iostream>
#include <string>
class DynamicArray
{
public:
DynamicArray()
: mCapacity(1), mNumberOfElements(0)
{
mArray = new std::string[mCapacity];
}
DynamicArray(int size)
: mCapacity(size), mNumberOfElements(0)
{
mArray = new std::string[mCapacity];
}
DynamicArray(const DynamicArray& array)
: mCapacity(array.getCapacity()), mNumberOfElements(array.length())
{
mArray = new std::string[mCapacity];
for (size_t i = 0; i < mCapacity; ++i)
{
mArray[i] = array.get(i);
}
}
~DynamicArray()
{
delete[] mArray;
}
void add(std::string element)
{
if (mNumberOfElements >= mCapacity)
{
expand();
}
mArray[mNumberOfElements++] = element;
}
std::string get(int index) const
{
if (index > mNumberOfElements)
{
std::string exception = std::to_string(index) + " index is out of bounds.";
std::cout << exception;
return std::string();
}
if (index < 0)
{
if (mNumberOfElements + index < 0)
{
std::string exception = std::to_string(index) + " index result in " + std::to_string(mNumberOfElements + index) + " which is out of bounds.\n";
std::cout << exception;
return std::string();
}
return mArray[mNumberOfElements + index];
}
return mArray[index];
}
int length() const
{
return mNumberOfElements;
}
int getCapacity() const
{
return mCapacity;
}
private:
int mCapacity;
int mNumberOfElements;
std::string* mArray;
void initialize(int from)
{
for (size_t i = from; i < mCapacity; ++i)
{
mArray[i] = std::string();
}
}
void expand()
{
mCapacity *= 2;
std::string* temporaryArray = new std::string[mCapacity];
for (size_t i = 0; i < mCapacity; ++i)
{
temporaryArray[i] = mArray[i];
}
delete[] mArray;
mArray = temporaryArray;
initialize(mNumberOfElements);
}
};
int main()
{
DynamicArray strings;
strings.add("Hello");
strings.add("World");
for (size_t i = 0; i < strings.length(); ++i)
{
std::cout << strings.get(i) << std::endl;
}
}
My output
$ clang++ tests/string-dynamic-array.cpp -o tests/string-dynamic-array && ./tests/string-dynamic-array
[1] 14950 segmentation fault (core dumped) ./tests/string-dynamic-array
I get a segmentation fault.
The issue as far as I've found is in the code where I expand the array, in the expand() function. I think it's in the for loop because the index of for loop is out of bounds of the original array.
I've tried this with int, it seems to work fine. How can I do this with strings?
As commented by UnholySheep.
I changed my expand function a bit so the loop only runs till the size of the old array.
Updated expand function:
void expand()
{
mCapacity *= 2;
std::string* temporaryArray = new std::string[mCapacity];
for (size_t i = 0; i < mNumberOfElements; ++i)
{
temporaryArray[i] = mArray[i];
}
delete[] mArray;
mArray = temporaryArray;
initialize(mNumberOfElements);
}
In “expand” method you have deleted mArray, then, you copied the temporaryArray to it, while as far as I know, mArray’s handle is not valid anymore. You need to pass temporaryArray‘s handle to mArray so you could use it as a new expanded array.
I am attempting to implement my own version of a C++ vector, but I'm having issues with my reallocation function when the size becomes equal to the capacity. Specifically, when the debugger reaches the delete line, I am given a heap corruption error stating that the application wrote to memory after the end of the heap buffer. Could someone give advice on why my approach is wrong? Please let me know if there is any other information needed that would be helpful in solving this issue.
EDIT: I have added all of my current code so that others can test the program and reproduce the issue.
Header file:
#ifndef VECTOR_H
#define VECTOR_H
template <class ItemType> class Vector{
public:
Vector();
Vector(int capacity);
int size();
int capacity();
bool is_empty();
ItemType at(int index);
void push(ItemType newItem);
void printItems();
~Vector();
private:
int m_capacity; // number of items we can hold
int m_size; // current number of items
int m_unitSize; // size of one unit (used for arithmetic in indexing)
ItemType* m_vectorPtr; // pointer to actual vector
void reallocate(); // reallocates memory if array is filled
};
#endif
Implementations and testing:
#include <iostream>
#include "Vector.h"
#include <assert.h>
// default constructor
template <class ItemType>
Vector<ItemType>::Vector()
:m_capacity(0), m_size(0) {
m_unitSize = sizeof(ItemType);
m_vectorPtr = nullptr;
}
// constructor with given number of items
template <class ItemType>
Vector<ItemType>::Vector(int capacity)
:m_size(0){
int x = 1;
while (x <= capacity) {
x *= 2;
}
m_unitSize = sizeof(ItemType);
m_capacity = x;
m_vectorPtr = new ItemType[capacity];
}
// return total possible items
template <class ItemType>
int Vector<ItemType>::capacity() {
return m_capacity;
}
// return current number of elements
template <class ItemType>
int Vector<ItemType>::size() {
return m_size;
}
// return whether the vector is currently empty
template <class ItemType>
bool Vector<ItemType>::is_empty() {
return m_size == 0;
}
// return the item at a given index
template<class ItemType>
ItemType Vector<ItemType>::at(int index) {
return m_vectorPtr[index];
}
// reallocate the array if it becomes full
template <class ItemType>
void Vector<ItemType>::reallocate() {
if (m_size >= m_capacity) {
// allocate a new array twice the capacity
m_capacity *= 2;
ItemType* newVector = new ItemType[m_capacity];
for (int i = 0; i < m_size; i++) {
newVector[i] = m_vectorPtr[i];
}
delete[] m_vectorPtr;
m_vectorPtr = newVector;
}
}
// push an item onto the vector at the end
template<class ItemType>
void Vector<ItemType>::push(ItemType newItem) {
if (m_size >= m_capacity) {
// reallocate memory for the vector
reallocate();
}
// push new item onto vector
m_vectorPtr[m_size] = newItem;
m_size++;
}
template <class ItemType>
void Vector<ItemType>::printItems() {
for (int i = 0; i < m_size; i++) {
std::cout << m_vectorPtr[i] << " ";
}
std::cout << std::endl;
}
template <class ItemType>
Vector<ItemType>::~Vector() {
delete[] m_vectorPtr;
}
// test here
int main() {
// initialize a vector
int startingCapacity = 3;
Vector<int> testVector(startingCapacity);
assert(testVector.capacity() == 4 &&
testVector.size() == 0 &&
testVector.is_empty() == true);
// add two items to the vector
testVector.push(3);
testVector.push(7);
assert(testVector.capacity() == 4 &&
testVector.size() == 2 &&
testVector.is_empty() == false);
// print the two items
testVector.printItems();
// add past capacity to test reallocate
testVector.push(5);
testVector.push(8);
testVector.push(6);
assert(testVector.capacity() == 8 &&
testVector.size() == 5 &&
testVector.is_empty() == false);
testVector.printItems();
std::cout << "All test cases passed." << std::endl;
return 0;
}
You have to reallocate before you change m_size because the for loop will be incorrect if m_size > m_capacity and you'll access m_vectorPtr past its size. And make sure the new capacity is big enough (m_capacity *= 2) > new_size
template <class ItemType>
void Vector<ItemType>::reallocate(size_t new_size) {
if (new_size > m_capacity) {
// allocate a new array twice the capacity
if (m_capacity == 0)
m_capacity = 10;
while (m_capacity < new_size)
m_capacity *= 2;
ItemType* newVector = new ItemType[m_capacity];
for (int i = 0; i < m_size; i++) {
newVector[i] = m_vectorPtr[i];
}
delete[] m_vectorPtr;
m_vectorPtr = newVector;
}
}
And here sample push_back method reallocating before changing m_size:
void push_back(ItemType item) {
reallocate(m_size + 1);
m_vectorPtr[m_size] = item;
m_size++;
}
Demo
UPDATE
You have a small bug in the constructor NOT:
m_vectorPtr = new ItemType[capacity];
but
m_vectorPtr = new ItemType[m_capacity];
because capacity is the requested one, not the power of two you want (3, not 4 in your test).
#include <iostream>
using namespace std;
template <typename T>
class DynamicArray
{
T *array;
unsigned int elements;
unsigned int size;
public:
void expand_array(int extra_size)
{
T *new_array= new T[size + extra_size];
//copy integers from old array
memcpy(new_array,array,elements*sizeof(T));
//make 0 the integers from new part of the array
memset(new_array + size, 0, extra_size * sizeof(T));
delete [] array;
array = new_array;
size += extra_size;
}
//constructors
DynamicArray()
{
array = new T[8];
elements = 0;
size = 8;
memset(array,0,size*sizeof(T));
}
DynamicArray(const unsigned int size)
{
array= new T[size];
}
virtual ~DynamicArray()
{
delete [] array;
}
void add(T new_element)
{
if(elements>=size)
expand_array(8);
array[elements++] = new_element;
}
int get (const unsigned int index) const
{
if(index< elements)
return array[index];
return -1;
}
void add(const unsigned int index, T new_element)
{
if(index>size)
expand_array(index- size +1);
array[index] = new_element;
elements = index +1;
}
DynamicArray &operator=(DynamicArray &ab)
{
elements=ab.elements;
size=ab.size;
if (this == &ab)
return *this;
delete array;
if(ab.array)
{
array= new T[size];
memcpy(array,ab.array,elements*sizeof(T));
}
else
{
array=0;
}
return *this;
}
DynamicArray(const DynamicArray& source)
{
elements=ab.elements;
size=ab.size;
if(ab.array)
{
array= new T[size];
memcpy(array,ab.array,elements*sizeof(T));
}
else
{
array=0;
}
}
};
int main()
{
DynamicArray<int> da(2);
DynamicArray<int> db(2);
DynamicArray< DynamicArray<int> > array_of_arrays(2);
array_of_arrays[0] = da;/
//array_of_arrays[1] = db;
/*
da[0]=5;
da[1]=2;
db[0]=3;
db[1]=4;
cout<<array_of_arrays[0][0]<<endl;
*/
system("color 0C");
system("pause");
return 0;
}
I need help in understanding why this gives me an error:
error C2676: binary '[' : 'DynamicArray<T>' does not define this operator or a conversion to a type acceptable to the predefined operator
i added this
T& operator[](unsigned int index)//important to provide this operator
{
if (index > size)
{
expand_array(index-size);
}
return array[index];
}
but subequently i got invalid allocation size error during runtime.I try to try it and figure that the problem is somewhere about this area
if(ab.array)
{
array= new T[size];
memcpy(array,ab.array,elements*sizeof(T));
}
but i have no idea why is that so.
Any ideas?
Thanks I figured it out: One of the attributes are not initialise to a proper valuein one of the constructors
DynamicArray(const unsigned int size)
.
Thanks for all the help.
The error has nothing to do with templates. The problem is that you use the [] operator on array_of_arrays. However the DynamicArray class does not define operator[].
What it does define is a method named add, so maybe you meant to call that instead? I.e. array_of_arrays.add(0, da); instead of array_of_arrays[0] = da;.
However it would probably be more idiomatic to simply define operator[] on your class.
DynamicArray does not define a subscript operator.
This would typically look like:
T& operator[] (unsigned int index)
{
if (index > size)
{
// Handle error
}
return array[index];
}
I have a technical problem and it's really confusing me. I apologise in advance because I may not be giving the relevant details; I don't yet why it's going wrong and it would be excessive to include all the code I'm working with.
I'm working with a large program that uses the C++ STL. I'm moving this code to a very sensitive environment without a standard clib nor STL implementaton; it will redefine malloc/free/new/delete etc... For that, I need to replace the std:: parts with my own simplified implementations. I've started with std::vector. Right now it's running in the standard ecosystem so it's the GNU libc and STL. The only thing that's changed is this vector class.
When I execute the program with the replaced class, it segfaults. I've put this through GDB and found that the program will request an object from the vector using the subscript operator. When the object reference is returned, a method is invoked and the program segfaults. It seems it can't find this method and ends up in main_arena() in GDB. The type of the object is an inherited class.
I'm really not sure at all what the problem is here. I would love to provide additional details, but I'm not sure what more I can give. I can only assume something is wrong with my vector implementation because nothing else in the program has been changed. Maybe there's something obvious that I'm doing wrong here that I'm not seeing at all.
I'm using: g++ (GCC) 4.4.5 20110214 (Red Hat 4.4.5-6)
I'd really appreciate any feedback/advice!
#ifndef _MYSTL_VECTOR_H_
#define _MYSTL_VECTOR_H_
#include <stdlib.h>
#include <assert.h>
typedef unsigned int uint;
namespace mystl
{
/******************
VECTOR
********************/
template <typename T>
class vector
{
private:
uint _size;
uint _reserved;
T *storage;
void init_vector(uint reserve)
{
if (reserve == 0)
{
_reserved = 0;
return;
}
storage = (T*)malloc(sizeof(T)*reserve);
assert(storage);
_reserved = reserve;
}
public:
vector()
{
// std::cerr << "default constructor " << this << std::endl;
storage = NULL;
_size = 0;
_reserved = 0;
}
vector(const vector<T> &other)
{
// std::cerr << "copy constructor " << this << std::endl;
storage = NULL;
_size = 0;
_reserved = 0;
init_vector(other.size());
_size = other.size();
for (uint i=0; i<other.size(); i++)
{
storage[i] = T(other[i]);
}
}
vector(uint init_num, const T& init_value)
{
// std::cerr << "special constructor1 " << this << std::endl;
storage = NULL;
_size = 0;
_reserved = 0;
init_vector(init_num);
for (size_t i=0; i<init_num; i++)
{
push_back(init_value);
}
}
vector(uint init_num)
{
// std::cerr << "special constructor2 " << this << std::endl;
storage = NULL;
_size = 0;
_reserved = 0;
init_vector(init_num);
}
void reserve(uint new_size)
{
if (new_size > _reserved)
{
storage = (T*)realloc(storage, sizeof(T)*new_size);
assert(storage);
_reserved = new_size;
}
}
void push_back(const T &item)
{
if (_size >= _reserved)
{
if (_reserved == 0) _reserved=1;
reserve(_reserved*2);
}
storage[_size] = T(item);
_size++;
}
uint size() const
{
return _size;
}
~vector()
{
if (_reserved)
{
free(storage);
storage = NULL;
_reserved = 0;
_size = 0;
}
}
// this is for read only
const T& operator[] (unsigned i) const
{
// do bounds check...
if (i >= _size || i < 0)
{
assert(false);
}
return storage[i];
}
T& operator[] (unsigned i)
{
// do bounds check...
if (i >= _size || i < 0)
{
assert(false);
}
return storage[i];
}
// overload = operator
const vector<T>& operator= (const vector<T>& x)
{
// check for self
if (this != &x)
{
_reserved = 0;
_size = 0;
storage = NULL;
init_vector( x.size() );
for(uint i=0; i<x.size(); i++)
{
storage[i] = T(x[i]);
}
_size = x.size();
}
return *this;
}
uint begin() const
{
return 0;
}
void insert(uint pos, const T& value)
{
push_back(value);
if (size() == 1)
{
return;
}
for (size_t i=size()-2; i>=pos&& i>=0 ; i--)
{
storage[i+1] = storage[i];
}
storage[pos] = value;
}
void erase(uint erase_index)
{
if (erase_index >= _size)
{
return;
}
//scoot everyone down by one
for (uint i=erase_index; i<_size; i++)
{
storage[i] = storage[i+1];
}
_size--;
}
void erase(uint start, uint end)
{
if (start > end)
{
assert(false);
}
if (end > _size)
end = _size;
for (uint i=start; i<end; i++)
{
erase(start);
}
assert(false);
}
void clear()
{
erase(0,_size);
}
bool empty() const
{
return _size == 0;
}
}; //class vector
}
#endif // _MYSTL_VECTOR_H_
Wow!
Your assignment operator also leaks memory.
Becuause you are using malloc/release the constructor to your type T will will not be called and thus you can not use your vector for anything except the most trivial of objects.
Edit:
I am bit bored this morning: Try this
#include <stdlib.h> // For NULL
#include <new> // Because you need placement new
// Because you are avoiding std::
// An implementation of swap
template<typename T>
void swap(T& lhs,T& rhs)
{
T tmp = lhs;
lhs = rhs;
rhs = tmp;
}
template <typename T>
class vector
{
private:
unsigned int dataSize;
unsigned int reserved;
T* data;
public:
~vector()
{
for(unsigned int loop = 0; loop < dataSize; ++loop)
{
// Because we use placement new we must explicitly destroy all members.
data[loop].~T();
}
free(data);
}
vector()
: dataSize(0)
, reserved(10)
, data(NULL)
{
reserve(reserved);
}
vector(const vector<T> &other)
: dataSize(0)
, reserved(other.dataSize)
, data(NULL)
{
reserve(reserved);
dataSize = reserved;
for(unsigned int loop;loop < dataSize;++loop)
{
// Because we are using malloc/free
// We need to use placement new to add items to the data
// This way they are constructed in place
new (&data[loop]) T(other.data[loop]);
}
}
vector(unsigned int init_num)
: dataSize(0)
, reserved(init_num)
, data(NULL)
{
reserve(reserved);
dataSize = reserved;
for(unsigned int loop;loop < dataSize;++loop)
{
// See above
new (&data[loop]) T();
}
}
const vector<T>& operator= (vector<T> x)
{
// use copy and swap idiom.
// Note the pass by value to initiate the copy
swap(dataSize, x.dataSize);
swap(reserved, x.rserved);
swap(data, x.data);
return *this;
}
void reserve(unsigned int new_size)
{
if (new_size < reserved)
{ return;
}
T* newData = (T*)malloc(sizeof(T) * new_size);
if (!newData)
{ throw int(2);
}
for(unsigned int loop = 0; loop < dataSize; ++loop)
{
// Use placement new to copy the data
new (&newData[loop]) T(data[loop]);
}
swap(data, newData);
reserved = new_size;
for(unsigned int loop = 0; loop < dataSize; ++loop)
{
// Call the destructor on old data before freeing the container.
// Remember we just did a swap.
newData[loop].~T();
}
free(newData);
}
void push_back(const T &item)
{
if (dataSize == reserved)
{
reserve(reserved * 2);
}
// Place the item in the container
new (&data[dataSize++]) T(item);
}
unsigned int size() const {return dataSize;}
bool empty() const {return dataSize == 0;}
// Operator[] should NOT check the value of i
// Add a method called at() that does check i
const T& operator[] (unsigned i) const {return data[i];}
T& operator[] (unsigned i) {return data[i];}
void insert(unsigned int pos, const T& value)
{
if (pos >= dataSize) { throw int(1);}
if (dataSize == reserved)
{
reserve(reserved * 2);
}
// Move the last item (which needs to be constructed correctly)
if (dataSize != 0)
{
new (&data[dataSize]) T(data[dataSize-1]);
}
for(unsigned int loop = dataSize - 1; loop > pos; --loop)
{
data[loop] = data[loop-1];
}
++dataSize;
// All items have been moved up.
// Put value in its place
data[pos] = value;
}
void clear() { erase(0, dataSize);}
void erase(unsigned int erase_index) { erase(erase_index,erase_index+1);}
void erase(unsigned int start, unsigned int end) /* end NOT inclusive so => [start, end) */
{
if (end > dataSize)
{ end = dataSize;
}
if (start > end)
{ start = end;
}
unsigned int dst = start;
unsigned int src = end;
for(;(src < dataSize) && (dst < end);++dst, ++src)
{
// Move Elements down;
data[dst] = data[src];
}
unsigned int count = start - end;
for(;count != 0; --count)
{
// Remove old Elements
--dataSize;
// Remember we need to manually call the destructor
data[dataSize].~T();
}
}
unsigned int begin() const {return 0;}
}; //class vector
With your current memory handling, this vector would only work with plain old data types.
To handle all types, it must ensure that objects
are actually created (malloc doesn't do that),
destroyed (free doesn't do that),
and you can't reallocate memory with realloc, because complex objects are not guaranteed to remain valid if they are byte-wise copied to another location.
Looks like the answer can be found in your question: "When the object reference is returned, a method is invoked and the program segfaults. It seems it can't find this method and ends up in main_arena() in GDB. The type of the object is an inherited class."
You probably store base class instance T in the vector, but make push_back for the instance of the class inherited from T. In push_back {storage[_size] = T(item);} you cast (actually make copy constructor T:T(const T&)) item to T (this probably named 'type cut'), then get reference to T and invoke a method of the class inherited from T using virtual table of T where the method is not defined yet/abstract. Am I right?
To make it properly work you should put T* in the vector or shared_ptr/unique_ptr depending on the ownership terms you apply to vector elements.
Generally in vector you can store only POD (Plain Old Data) types.