I want to make "set" function. This function changes the values of a2 from "set(int x, int y)" to "y"
#include <iostream>
using namespace std;
class IntArray {
private:
int* m_data;
int m_len;
public:
IntArray(int = 0, int = 0);
~IntArray();
void print(void);
IntArray(const IntArray& copy); // copy Constructor
void set(int x , int y) {
int temp = x;
x = y;
y = temp;//!!
}
};
IntArray::IntArray(int size, int init) {
if (size <= 0) {
m_data = nullptr; m_len = 0;
}
else {
m_data = new int[size];
m_len = size;
for (int idx = 0; idx < m_len; ++idx)
*(m_data + idx) = init;
}
}
IntArray::~IntArray() {
delete[]m_data;
}
void IntArray::print(void) {
for (int idx = 0; idx < m_len; ++idx)
cout << *(m_data + idx) << ' ';
cout << std::endl;
}
int main() {
cout << "a1: ";
IntArray a1{ 10, 100 };
a1.print();
cout << "a2: ";
IntArray a2{ a1 };// 10~100
a2.set(3, 999);
a2.set(9, 123);
a2.print();
return 0;
}
Excepted
a1: 100 100 100 100 100 100 100 100 100 100
a2: 100 100 100 999 100 100 100 100 100 123
Here's what you need.
let's fix up your declaration and introduce two new helper methods, alloc and copyFromOther.
class IntArray {
private:
int* m_data;
int m_len;
void alloc(int len);
void copyFromOther(const IntArray& copy);
public:
IntArray();
IntArray(const IntArray& copy);
~IntArray();
IntArray& operator=(const IntArray& copy);
void print();
void set(int index, int value);
};
Then the helper methods are for quick allocations and copy. Notice that I didn't special case length == 0. That's because it's perfectly fine to say, new int[0]. It will allocate a pointer of zero length. You can change this if you want to force a null pointer when length is zero. Also be aware that copy constructors need to be able to handle "copying to yourself". That is, if you say:
IntArray arr(10, 20);
arr.set(5,5);
arr = arr;
As weird as the above looks, it's the source of a lot of bugs when a copy constructor doesn't handle that case. That's covered below.
So now the implementation
void IntArray::alloc(int len) {
delete [] m_data; // erase what we had before
m_data = new int[len]; // you could say m_data = len ? new int[len] : nullptr
m_len = len;
}
void IntArray::copyFromOther(const IntArray& copy) {
// special case - allow for "copying to ourselves" by doing nothing
// if we didn't handle this, the alloc function would delete the pointer
if (copy.m_data == m_data) {
return;
}
alloc(copy.m_len);
for (int idx = 0; idx < m_len; ++idx)
m_data[idx] = copy.m_data[idx];
}
}
Then the implementation
IntArray::IntArray() : m_data(nullptr) {
alloc(0);
}
IntArray::IntArray(const IntArray& copy) m_data(nullptr), m_len(0) {
copyFromOther(copy);
}
IntArray& IntArray::operator=(const IntArray& copy) {
copyFromOther(copy);
return *this;
}
And let's fix your set method as you had asked about it in a separate question:
void IntArray::set(int index, int value) {
if ((index >= 0) && (index < m_len)) {
m_data[index] = value;
}
}
Your destructor and print methods are fine as you have them. print doesn't need to have an explicit void parameter.
Related
Everything seems to be copying fine, but when I call array2.print(), it shows segmentation fault. What am I doing wrong?
#include <iostream>
#include <initializer_list>
template <typename T>
class DynamicArray
{
private:
const int GROWTH_FACTOR = 2;
const int INITIAL_CAPACITY = 5;
T *m_array;
int m_capacity; // Capacity of the array
int m_size; // Number of added elements
public:
DynamicArray(std::initializer_list<T> elements)
: m_size(elements.size())
, m_capacity(elements.size() * 2)
{
m_array = new T[m_capacity];
std::copy(elements.begin(), elements.end(), m_array);
}
DynamicArray()
: m_size(0)
, m_capacity(INITIAL_CAPACITY)
{
m_array = new T[m_capacity];
}
~DynamicArray()
{
delete[] m_array;
}
DynamicArray(const DynamicArray& other)
: GROWTH_FACTOR(other.GROWTH_FACTOR)
, INITIAL_CAPACITY(other.INITIAL_CAPACITY)
, m_capacity(other.m_capacity)
, m_size(other.m_size)
{
T *m_array = new T[m_capacity];
std::copy(other.m_array, other.m_array + m_size, m_array);
}
int size()
{
return m_size;
}
int capacity()
{
return m_capacity;
}
void resize()
{
int new_capacity = m_capacity * GROWTH_FACTOR;
m_capacity = new_capacity;
T *temp = new T[new_capacity];
std::copy(m_array, m_array + m_capacity, temp);
delete[] m_array;
m_array = temp;
}
void deleteAt(int pos)
{
for (int i = pos; i < m_size - 1; i++)
{
(*this)[i] = (*this)[i + 1];
}
m_size--;
}
void insertAt(T value, int pos)
{
if (m_capacity == m_size)
{
resize();
}
for (int i = m_size - 1; i >= pos; i--)
{
(*this)[i + 1] = (*this)[i];
}
m_size++;
(*this)[pos] = value;
}
void append(T value)
{
insertAt(value, m_size);
}
void print() {
for (int i = 0; i < m_size; i++)
{
std::cout << (*this)[i] << ", ";
}
std::cout << std::endl;
}
T& operator[](int index)
{
if (index < 0 || index > m_size - 1)
{
throw std::invalid_argument("Index out of range!");
}
return m_array[index];
}
};
int main()
{
DynamicArray<int> array = { 1, 2, 3, 4 };
DynamicArray<int> array2 = array;
array2.print();
return 0;
}
The error is here
T *m_array = new T[m_capacity];
It should be
m_array = new T[m_capacity];
By declaring a new variable called m_array you hid the class member variable that you wanted to assign to. The technical name for this is shadowing, a good compiler would warn you about this.
You redeclare m_array in the cctor, which shadows the class member.
I'm very new to C++ so please excuse the sloppy code.
Here is the code in question:
Bag Class
class Bag {
protected:
Item* _myItems;
int _numItems;
int _size;
public:
Bag();
Bag(int size);
~Bag();
Bag(Bag& original);
void add(Item a);
void remove(int itemnum);
int size();
int numItems();
void operator=(Bag& bag);
Item& operator[] (int i);
};
//Empty constructor
Bag::Bag() {
_numItems = 0;
}
//overloaded constructor
Bag::Bag(int size) {
_numItems = 0;
_myItems = new Item[size];
}
//copy constructor
Bag::Bag(Bag& original) {
//Copies the numItems
_numItems = original._numItems;
//Makes a new copy of the original array
_myItems = new Item[_numItems];
//Copies each element of the original into the new
for (int i = 0; i < _numItems; ++i) {
_myItems[i] = original[i];
}
}
//Destructor
Bag::~Bag(){
delete[] _myItems;
}
//Returns the size of the bag
int Bag::size()
{
return _size;
}
//Returns the number of items in the bag
int Bag::numItems() {
return _numItems;
}
//Add a new item to the bag
void Bag::add(Item a) {
int s = _numItems;
//Create a Item pointer and assign it to the array of the bag
Item* temp = _myItems;
//Assign _myItems to a new, larger array
_myItems = new Item[_numItems++];
//Copy the old array into the new one and nullify all the old array's items
for (int i = 0; i < _numItems - 1; i++) {
_myItems[i] = temp[i];
}
//Destroy the old array
delete[] temp;
//Add the item to the last position
_myItems[_numItems] = a;
}
I am reading a text file line by line. The reading seems to be happening just fine. When I read in I execute this part of the code:
//The main program
int main() {
Pens * onePen = new Pens(1, 2);
Pens * twoPen = new Pens(2, 3);
Bag* bag = new Bag(5);
(*bag).add(onePen);
(*bag).add(twoPen);
bag[0];
bag[1];
int d = 0;
return 0;
}
I keep getting the Read Access Violation (This was 0xc) when I get into the add method. I also notice that when I put in breakpoints to examine the code, _numItems is not 0 but 211. Am I corrupting my memory somehow?
Here is a sample text file that we are using
Simplified version of the Bag and Pen classes (courtesy of PaulMcKenzie):
class Item {
protected:
int code_;
//Sets the method definition for the get/set methods and constructors
public:
Item(int code = -1);
virtual ~Item() {}
int getcode() const;
void setcode(int code);
std::ostream& operator<< (std::ostream& s);
bool operator== (const Item& a) const;
};
Item::Item(int code) : code_(code) {}
int Item::getcode() const { return code_; }
void Item::setcode(int code) { code_ = code; }
std::ostream & Item::operator<<(std::ostream& s)
{
s << " Code - " << code_ << "\n";
return s;
}
bool Item::operator==(const Item & a) const
{
return (code_ == a.getcode());
}
class Pens : public Item
{
private: int packetsize_;
public:
Pens();
Pens(int code, int packetsize);
int getpacketsize() const;
void setpacketsize(int packetsize);
bool operator== (const Pens& a) const;
};
Pens::Pens() :Item() { }
Pens::Pens(int code, int packetsize) : Item(code), packetsize_(packetsize) {}
int Pens::getpacketsize() const { return packetsize_; }
void Pens::setpacketsize(int packetsize) { packetsize_ = packetsize; }
std::ostream& operator<<(std::ostream& s, const Pens& pen)
{
s << " Packet size: " << pen.getpacketsize() << "\n";
return s;
}
bool Pens::operator==(const Pens & a) const
{
return code_ == a.getcode() && packetsize_ == a.getpacketsize();
}
I did not look in depth but this segment caught my eye:
//Add a new item to the bag
void Bag::add(Item a) {
int s = _numItems;
//Create a Item pointer and assign it to the array of the bag
Item* temp = _myItems;
//Assign _myItems to a new, larger array
_myItems = new Item[_numItems++];
//Copy the old array into the new one and nullify all the old array's items
for (int i = 0; i < _numItems - 1; i++) {
_myItems[i] = temp[i];
}
//Destroy the old array
delete[] temp;
//Add the item to the last position
_myItems[_numItems] = a;
}
Please look at this line:
_myItems = new Item[_numItems++];
You create new array with size of _numItems and then increase the _numItems by 1.
Which in my humble opinion leaves you with array of size _numItems-1.
And then you try to use element _myItems[_numItems] so this may be the reason of memory corruption.
I'm a beginner when it comes to C++ and have recently ran in to a very frustrating problem with my small program where I'm practicing operator overloading and templates.
I've created a template-class called SortedVector that can store instances of various types.
using namespace std;
template <class T, int size> class SortedVector {
public:
SortedVector();
bool add(const T& v);
T& median();
void sortArray();
void removeLarge(const T& v);
void print(ostream &os);
void compexch(T& x, T& y);
void sortArray(T* data, int s);
private:
T arr[size];
int arraySize;
};
template <class T, int size> SortedVector<T, size>::SortedVector() {
arraySize = 0;
for (int i = 0; i < size; i++) {
arr[i] = T();
}
}
template <class T, int size> bool SortedVector<T, size>::add(const T& v) {
if (arraySize > size - 1) {
cout << "Array is full!" << endl;
return false;
} else {
arr[arraySize] = v;
arraySize++;
sortArray(arr, arraySize);
}
return true;
}
template <class T, int size> void SortedVector<T, size>::sortArray(T* data, int s) {
for (int i = 0; i < s - 1; i++) {
for (int j = i + 1; j < s; j++) {
compexch(data[i], data[j]);
}
}
}
template <class T, int size > T & SortedVector<T, size>::median() {
}
template <class T, int size> void SortedVector<T, size>::removeLarge(const T & v) {
}
template <class T, int size> void SortedVector<T, size>::print(ostream & os) {
for (int i = 0; i < arraySize; i++) {
cout << arr[i] << endl;
}
}
template <class T, int size> inline void SortedVector<T, size>::compexch(T& x, T& y) {
if (y < x) {
T temp = x;
x = y;
y = temp;
}
}
It can store ints succesfully and it can also store Polygons (a custom made class created in a earlier assignment).
Polygon.h:
class Polygon {
public:
Polygon(Vertex vertexArray[], int size);
Polygon() : vertices(0), arraySize(0) {}
~Polygon() {delete[] vertices;}
void add(Vertex v);
float area();
int minx();
int maxx();
int miny();
int maxy();
int numVertices() const {return arraySize;}
friend ostream &operator << (ostream &output, const Polygon& polygon);
friend bool operator > (Polygon polygon1, Polygon polygon2);
friend bool operator < (Polygon polygon1, Polygon polygon2);
private:
int arraySize;
Vertex * vertices;
};
Polygon.cpp declaration:
using namespace std;
void Polygon::add(Vertex v) {
arraySize++;
Vertex * tempVertexes = new Vertex[arraySize];
for (int i = 0; i < arraySize; i++) {
if (i == arraySize - 1) {
tempVertexes[i] = v;
} else {
tempVertexes[i] = vertices[i];
}
}
delete [] vertices;
vertices = tempVertexes;
}
Polygon::Polygon(Vertex vertexArray[], int size) {
arraySize = size;
vertices = new Vertex[size];
for (int i = 0; i < size; i++) {
vertices[i] = vertexArray[i];
}
}
float Polygon::area() {
float area = 0.0f;
for (int i = 0; i < arraySize - 1; ++i) {
area += (vertices[i].getXposition() * vertices[i + 1].getYposition()) - (vertices[i + 1].getXposition() * vertices[i].getYposition());
}
area += (vertices[0].getYposition() * vertices[arraySize - 1].getXposition()) - (vertices[arraySize - 1].getYposition() * vertices[0].getXposition());
area = abs(area) *0.5;
return area;
}
ostream& operator<<(ostream &output, const Polygon& polygon) { //Kolla denna!
output << "{";
for (int i = 0; i < polygon.numVertices(); i++) {
output << "(" << polygon.vertices[i].getXposition() << "," << polygon.vertices[i].getYposition() << ")";
}
output << "}";
return output;
}
bool operator>(Polygon polygon1, Polygon polygon2) {
if (polygon1.area() > polygon2.area()) {
return true;
} else {
return false;
}
}
bool operator<(Polygon polygon1, Polygon polygon2) {
if (polygon1.area() < polygon2.area()) {
return true;
} else {
return false;
}
}
template <class T> inline void compexch(T& x, T& y) {
if (y < x) {
T temp = x;
x = y;
y = temp;
}
}
The code for the Vertex class:
class Vertex {
public:
Vertex() : y(0), x(0) {}
Vertex(int xPosition, int yPosition) : x(xPosition), y(yPosition) {}
~Vertex() {}
int getXposition() const {return x;}
int getYposition() const {return y;}
private:
int x;
int y;
};
The problem however is that the overloaded <<-operator seems print out the wrong values from the main-method:
int main() {
SortedVector<Polygon, 10> polygons;
SortedVector<int, 6> ints;
ints.add(3);
ints.add(1);
ints.add(6);
Vertex varr[10];
varr[0] = Vertex(0, 0);
varr[1] = Vertex(10, 0);
varr[2] = Vertex(5, 2);
varr[3] = Vertex(5, 5);
polygons.add(Polygon(varr, 4));
cout << "varr area:" << (Polygon(varr, 4)).area() << endl;
varr[0] = Vertex(0, 0);
varr[1] = Vertex(25, 8);
varr[2] = Vertex(10, 23);
polygons.add(Polygon(varr, 3));
cout << "var area (1):" << (Polygon(varr, 3)).area() << endl;
varr[0] = Vertex(0, 0);
varr[1] = Vertex(5, 0);
varr[2] = Vertex(5, 3);
varr[3] = Vertex(4, 8);
varr[4] = Vertex(2, 10);
polygons.add(Polygon(varr, 5));
cout << "var area (2):" << (Polygon(varr, 5)).area() << endl;
polygons.print(cout);
ints.print(cout);
cout << "MEDIAN: " << ints.median() << endl;
cout << "MEDIAN: " << polygons.median() << endl;
return 0;
}
The code that is printed is:
var area (1):247.5
var area (2):33.5
{(6029504,0)(5,0)(5,3)}
{(6029504,0)(5,0)(5,3)(4,8)}
{(6029504,0)(5,0)(5,3)(4,8)(2,10)}
1
3
6
MEDIAN: 1
MEDIAN: {(6029504,0)(5,0)(5,3)}
Firstly, the method prints out the same polygon but with varying sizes. Secondly, it points out the wrong getXPosition() for the first object in the array. Everything else (that is implemented, like the ints and the area) is correct tho. Why is this? Am I missing something important here or am I just completely of with my program?
If theres any more code needed I am happy to provide it.
Regards
Given the code you posted, the issues are clear as to what's wrong.
You're passing Polygon's by value here:
friend bool operator > (Polygon polygon1, Polygon polygon2);
friend bool operator < (Polygon polygon1, Polygon polygon2);
and you're copying and assigning values here in: compexch:
if (y < x) {
T temp = x; // copy constructor
x = y; // assignment
y = temp; // assigment
}
This means that copies will be made, and your Polygon class cannot be copied safely. You will have memory leaks and bugs when calling either of these functions.
You should implement the appropriate copy constructor and assignment operator, whose signatures are:
Polygon(const Polygon& rhs); // copy constructor
Polygon& operator=(const Polygon& rhs); // assignment operator
Both of these functions should be implemented. Please see the Rule of 3 for this information.
However, for operator < and operator >, you should pass references, not values to these functions:
friend bool operator > (Polygon& polygon1, Polygon& polygon2);
friend bool operator < (Polygon& polygon1, Polygon& polygon2);
Then the copy constructor and assignment operator are not brought into play, since the parameter type is a reference.
Let's try to implement the copy / assignment functions anyway, for completeness:
For example, the copy constructor can be implemented like this:
Polygon::Polygon(const Polygon& rhs) : vertices(new int[rhs.arraySize]),
arraySize(rhs.arraySize)
{
for (int i = 0; i < arraySize; ++i)
vertices[i] = rhs.vertices[i];
}
Then for the assignment operator, using the copy / swap idiom:
Polygon& operator=(const Polygon& rhs)
{
Polygon temp(rhs);
std::swap(temp.arraySize, arraySize);
std::swap(temp.vertices, vertices);
return *this;
}
Once you've implemented these function, plus the destructor that calls delete[], you should no longer have an issue with copying the objects.
Other issues:
In addition, you really should only overload < and ==, initially with their "full" implementation, and write the other relational operators with respect to these two operators.
Right now, you're making the classic mistake of writing one operator (operator >), and then trying to turn the logic "inside-out" when implementing operator <. What if the logic for operator > were more complex, and it took yeoman's work to figure out what is the "opposite of <"?
If you implemented ==, then operator > just becomes:
return !(polygon1 < polygon2) && !(polygon == polygon2); // <-- this can be further improved by implementing operator !=
can somebody ewxplain me how the compiler calls the operator casting:
operator ELEMENT()const {
return pArray->arr[index];
}
From line 6 in main:
(*ptr3)[0] = a1[0] + a2[1];
How adding two ELEMENT object with + operator even allowed? There is no + operator overloading in ELEMENT class.
Thanks,
Liron
#include <iostream>
using namespace std;
template<class ELEMENT> class Array
{
class Element
{
Array<ELEMENT>* pArray;
int index;
public:
Element(Array<ELEMENT>* p, int i)
: pArray(p), index(i) {}
const Element& operator=(const ELEMENT& e) {
pArray->set(index, e); // call copy-on-write
return *this;
}
operator ELEMENT()const {
return pArray->arr[index];
}
};
friend class Element;
ELEMENT* arr;
int size;
int* ref_counter;
void attach(const Array& a) {
arr = a.arr; size = a.size;
ref_counter = a.ref_counter;
++(*ref_counter);
}
void detach() {
if(--(*ref_counter) == 0) {
delete []arr;
delete ref_counter;
}
}
void set(int index, const ELEMENT& e) {
if(*ref_counter > 1) { // need copy-on-write!
Array temp = clone();
detach();
attach(temp);
}
arr[index] = e;
}
public:
explicit Array(int);
Array<ELEMENT> clone()const;
Array(const Array<ELEMENT>& a){attach(a);}
~Array(){detach();}
const Array& operator=(const Array<ELEMENT>& a) {
detach(); attach(a); return *this;
}
Element operator[](int index) {
return Element(this, index);
}
const ELEMENT& operator[](int index)const {
return arr[index];
}
};
template<class ELEMENT>
Array<ELEMENT>::Array(int size1)
: size(size1), ref_counter(new int(1))
{
arr = new ELEMENT[size];
}
template<class ELEMENT>
Array<ELEMENT> Array<ELEMENT>::clone()const {
Array temp(size);
for(int i=0; i<size; ++i) {
temp.arr[i] = arr[i];
}
return temp;
}
int main()
{
Array<int> a1(1), a2(2);
Array<int>* ptr3 = new Array<int>(3);
a2[0] = 1;
a2[1] = 2;
a1 = a2;
(*ptr3)[0] = a1[0] + a2[1];
(*ptr3)[1] = a1[1] + a2[0];
cout << (*ptr3)[0] << ", " << (*ptr3)[1] << endl;
delete ptr3;
return 1;
}
How adding two ELEMENT object with + operator even allowed? There is no + operator overloading in ELEMENT class.
ELEMENT is not a class, it's a type parameter. And in your example the type given for that parameter is int. Obviously int does have a + operator, so that works fine. If you tried to create an Array<SomeType> where SomeType did not have a + operator, you would get an error.
There is an Element class and that class does indeed have no + operator, but that class is implicitly convertible to ELEMENT (i.e. int in this case), so when you apply + to objects of the Element the compiler adds a call to that conversion operator and + is applied to the result.
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.