So, I'm trying to convert an array class to a template class, so far I have combined the header and main file code into one, resulting in just the header file with all the .cpp code. Though trying to compile the code into the main file results in countless errors. Now, please go easy on me here, I am still coming to grasp with C++ here, and some of the higher functions and abilities go over my head, so I apologize in advance that I am not super familiar with all the functions. The code is below.
#ifndef ARRAY_H
#define ARRAY_H
#include <iostream>
#include <iomanip>
#include <stdexcept>
using namespace std;
template <typename GArray>
class Array
{
friend std::ostream &operator<<(std::ostream &, const Array &);
friend std::istream &operator>>(std::istream &, Array &);
public:
// default constructor for class Array (default size 3)
template <typename GArray> Array::Array(int arraySize)
: size(arraySize > 0 ? arraySize :
throw invalid_argument("Array size must be greater than 0")),
ptr(new int[size])
{
for (size_t i = 0; i < size; ++i)
ptr[i] = 0; // set pointer-based array element
} // end Array default constructor
template <typename GArray> Array::~Array()
{
delete[] ptr; // release pointer-based array space
} // destructor
size_t Array::getSize() const
{
return size; // number of elements in Array
} // end function getSize
// overloaded assignment operator;
// const return avoids: ( a1 = a2 ) = a3
template <typename GArray> const Array &Array::operator=(const Array &right)
{
if (&right != this) // avoid self-assignment
{
// for Arrays of different sizes, deallocate original
// left-side Array, then allocate new left-side Array
if (size != right.size)
{
delete[] ptr; // release space
size = right.size; // resize this object
ptr = new int[size]; // create space for Array copy
} // end inner if
for (size_t i = 0; i < size; ++i)
ptr[i] = right.ptr[i]; // copy array into object
} // end outer if
return *this; // enables x = y = z, for example
} // end function operator=
template <typename GArray> bool operator==(const Array &) const; // equality operator
// subscript operator for const objects returns rvalue
int operator[](int) const;
private:
size_t size;
int *ptr;
};
template <typename GArray> bool Array::operator==(const Array &right) const
{
if (size != right.size)
return false; // arrays of different number of elements
for (size_t i = 0; i < size; ++i)
if (ptr[i] != right.ptr[i])
return false; // Array contents are not equal
return true;
}
template <typename GArray> int Array::operator[](int subscript) const
{
if (subscript < 0 || subscript >= size)
throw out_of_range("Subscript out of range");
return ptr[subscript];
}
template <typename GArray> istream &operator>>(istream &input, Array &a)
{
for (size_t i = 0; i < a.size; ++i)
input >> a.ptr[i];
return input; // enables cin >> x >> y;
}
template <typename GArray> ostream &operator<<(ostream &output, const Array &a)
{
// output private ptr-based array
for (size_t i = 0; i < a.size; ++i)
{
output << setw(12) << a.ptr[i];
if ((i + 1) % 4 == 0) // 4 numbers per row of output
output << endl;
}
if (a.size % 4 != 0) // end last line of output
output << endl;
return output; // enables cout << x << y;
}
#endif
Firstly
If you define a class as a template, you do not need to tell the member functions declaration to be template. Just make them template in the definition and use them in your class template argument if they are defined outside the class. For example,
template <class T> class Test {
void func1(T arg1);
};
template <class T> Test<T>::func1(T arg1) {
// Your definition here
}
Or inside the class,
template <class T> class Test {
void func1(T arg1) {
//Your definition here
}
};
So you need to remove those from your code.
Secondly
Your class has two friend functions. In my opinion, they should also be template functions to work properly with your class. You can see here for a good knowledge in friend function in template classes.
Some good resources to know how to convert regular class to template
Converting regular class to template
I learned from here
Best place for c++ template tutorial
Finally
Although what I understand what you want, there should be added a lot more functionality to the class to work properly, after some modification, here is the code that is compilable and can be used as a starting point to know about your errors.
#ifndef ARRAY_H
#define ARRAY_H
#include <iostream>
#include <iomanip>
#include <stdexcept>
using namespace std;
template <typename GArray>
class Array {
private:
size_t size;
int *ptr;
public:
Array(int arraySize);
~Array();
size_t getSize() const;
const Array& operator=(const Array &right);
bool operator==(const Array &) const;
int operator[](int) const;
friend std::ostream &operator<<(std::ostream &, const Array &);
friend std::istream &operator>>(std::istream &, Array &);
};
template <typename GArray> bool Array<GArray>::operator==(const Array<GArray> &right) const
{
if (size != right.size)
return false; // arrays of different number of elements
for (size_t i = 0; i < size; ++i)
if (ptr[i] != right.ptr[i])
return false; // Array contents are not equal
return true;
}
template <typename GArray> int Array<GArray>::operator[](int subscript) const
{
if (subscript < 0 || subscript >= size)
throw out_of_range("Subscript out of range");
return ptr[subscript];
}
template <typename GArray> istream &operator>>(istream &input, Array<GArray> &a)
{
for (size_t i = 0; i < a.size; ++i)
input >> a.ptr[i];
return input; // enables cin >> x >> y;
}
template <typename GArray> ostream &operator<<(ostream &output, const Array<GArray> &a)
{
// output private ptr-based array
for (size_t i = 0; i < a.size; ++i)
{
output << setw(12) << a.ptr[i];
if ((i + 1) % 4 == 0) // 4 numbers per row of output
output << endl;
}
if (a.size % 4 != 0) // end last line of output
output << endl;
return output; // enables cout << x << y;
}
template<typename GArray>
Array<GArray>::Array(int arraySize)
: size(arraySize > 0 ? arraySize :
throw invalid_argument("Array size must be greater than 0")),
ptr(new int[size]) {
for (size_t i = 0; i < size; ++i)
ptr[i] = 0; // set pointer-based array element
}
template<typename GArray>
Array<GArray>::~Array() {
//This should be like this
for (int i = 0; i < size; ++i) {
delete ptr[i];
}
// delete[] ptr; // release pointer-based array space
}
template <typename GArray>
size_t Array<GArray>::getSize() const {
return size; // number of elements in Array
}
template<typename GArray>
const Array<GArray> &Array<GArray>::operator=(const Array &right) {
if (&right != this) // avoid self-assignment
{
// for Arrays of different sizes, deallocate original
// left-side Array, then allocate new left-side Array
if (size != right.size)
{
delete[] ptr; // release space
size = right.size; // resize this object
ptr = new int[size]; // create space for Array copy
} // end inner if
for (size_t i = 0; i < size; ++i)
ptr[i] = right.ptr[i]; // copy array into object
} // end outer if
return *this; // enables x = y = z, for example
}
#endif
Related
vector<int> a = {1,2,3};
a[1] = 54; // I want to achieve this in my Darray implementation
int i = 0;
a[i] = 10 // This also
I am trying to implement dynamic arrays in c++. Below is my code :
//-------- means it has not been defined yet
// custom Exception class for handling bizzare situations
#include <iostream>
using namespace std;
class MyException {
public:
MyException() {
cout << "\nException occured !! Program will terminate...\n";
exit(0);
}
MyException(string message) {
cout << "\nException occured : " << message
<< ".\nProgram will terminate...\n";
exit(0);
}
};
//================================================================================
// class for Dyanamic array
template <typename T> //
class Darray {
T *arr; // Dyanamic array
size_t len, cap; // length and capacity
/*
len : number of elements currently Darray contains
cap : number of elements Darray can hold without resizing
*/
public:
Darray();
Darray(size_t);
Darray(Darray<T> &);
// Darray(T *); //---------------
size_t capacity();
size_t length();
void resize(size_t);
bool empty();
T operator[](int);
T operator[](T);
void operator=(T); //-------------
void operator=(Darray);
void push(T);
T pop();
T back();
T elemAt(int);
T front();
T *data();
void assign(Darray); //---------------
void assign(T *); //--------------
void insertAt(T, int); //--------------
void erase(); //-------------
void clear(); //---------------
void swap(Darray, Darray); //---------
};
//================================================================================
// default constructor for 0 capacity
template <typename T> //
Darray<T>::Darray() {
arr = new T[0];
len = 0;
cap = 0;
}
//================================================================================
// parameterized constructor with given cap
template <typename T> //
Darray<T>::Darray(size_t cap) {
arr = new T[cap];
this->cap = cap;
len = 0; // no elements initially
}
//================================================================================
// copy constructor with given Darray
template <typename T> //
Darray<T>::Darray(Darray<T> &temp) {
cap = temp.capacity();
len = 0;
arr = new T[cap];
while (len < temp.length()) {
arr[len] = temp[len];
len++;
}
}
//================================================================================
// operator[] for getting elements
template <typename T> //
T Darray<T>::operator[](int index) {
if (empty())
throw MyException("Darray is empty");
if (index < 0 || index > len - 1)
throw MyException("Invalid index. Index should be in range 0 to length-1");
return arr[index];
}
//================================================================================
// to check if Darray is empty
template <typename T> //
bool Darray<T>::empty() {
return len < 1;
}
//================================================================================
// push elements at the end
template <typename T> //
void Darray<T>::push(T element) {
if (len == cap)
resize(cap + (cap / 2) + 1); // resizing the array
// +1 to ensure arrays of size 0 or 1 are also resized ;-)
arr[len] = element;
len++;
}
//================================================================================
// remove and gives the last element of Darray
template <typename T> //
T Darray<T>::pop() {
if (empty())
throw MyException("Darray is empty");
return arr[--len];
}
//================================================================================
// gives the last element of Darray
template <typename T> //
T Darray<T>::back() {
if (empty())
throw MyException("Darray is empty");
return arr[len - 1];
}
//================================================================================
// gives the first element of Darray
template <typename T> //
T Darray<T>::front() {
if (empty())
throw MyException("Darray is empty");
return arr[0];
}
//================================================================================
// gives element at pos
template <typename T> //
T Darray<T>::elemAt(int index) {
if (empty())
throw MyException("Darray is empty");
if (index < 0 || index > len - 1)
throw MyException("Invalid index. Index should be in range 0 to length-1");
return arr[index];
}
//================================================================================
// length gives number of elements currently present in the array
template <typename T> //
size_t Darray<T>::length() {
return len;
}
//================================================================================
// capacity gives total capacity of the array
template <typename T> //
size_t Darray<T>::capacity() {
return cap;
}
//================================================================================
// returns a pointer to first element of Darray
template <typename T> //
T *Darray<T>::data() {
if (empty())
return NULL;
return arr;
}
//================================================================================
// resize the array to given size
template <typename T> //
void Darray<T>::resize(size_t newSize) {
if (newSize < 0)
throw MyException("Size cannot be negative");
if (newSize == cap) // no need to resize
return;
T *temp; // temp array to hold the elements temporarily
size_t t; // t holds the number of elements to be copied in the resized Darray
if (newSize < len) {
t = newSize;
temp = new T[newSize];
// copying to temp,new size is less, some elements will be lost
for (int i = 0; i < t; i++) {
temp[i] = arr[i];
}
} else {
t = len;
temp = new T[len];
// copying all the elements from original array to temp
for (int i = 0; i < t; i++) {
temp[i] = arr[i];
}
}
arr = new T[newSize]; // resizing the Darray
// copying elements from temp to original Darray
for (int i = 0; i < t; i++) {
arr[i] = temp[i];
}
cap = newSize;
len = t;
}
int main()
{
Darray<char> a(0);
a.push('A');
a.push('B');
a.push('C');
a.push('D');
a.push('E');
// a.push('F');
// a.push('G');
// a.push('H');
for (int i = 0; i < a.length(); i++) {
cout << a[i] << " ";
}
cout << a.length() << " " << a.capacity() << endl;
return 0;
}
Is overloading the assignment operator to assign elements at given index of my dynamic array possible?
Something like:
Darray<int> a(5);
a[1] = 26;
Also if I overload the constructor to take array as T* and create a Darray(0) it becomes ambiguous (null pointer and Darray of size 0).
How to overcome this?
Your subscript operator returns by value. That means it returns a brand new copy.
Assigning to this copy will not change the original inside your "array".
You should return by reference instead:
T& operator[](int);
And you should probably add a "constant" overload as well:
T const& operator[](int) const;
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 !=
I'm sorry if the following code is long, but I don't know what is relevant to the problem and what is not.
#include <iostream>
#include <cmath>
#include <cstdio>
using namespace std;
template <class T>
class Array;
template <typename T>
ostream& operator<< (ostream &output, Array<T> &obj);
template <class T>
class Array {
private:
int capacity;
public:
T *arr;
Array();
Array(int);
~Array();
void Erase();
T& operator[](int);
friend ostream& operator<< <>(ostream &output, Array &obj);
int GetLength();
};
/* Constructors and Destructors */
template <class T>
Array<T>::Array() {
capacity = 0;
arr = new T [capacity];
}
template <class T>
Array<T>::Array(int n) {
capacity = n;
arr = new T [capacity];
}
template <class T>
Array<T>::~Array() {
delete [] arr;
}
/* End of Constructors and Destructors */
/* Member Functions */
template <class T>
void Array<T>::Erase() {
delete [] arr;
capacity = 0;
arr = new T [capacity];
}
template <class T>
int Array<T>::GetLength() {
return capacity;
}
/* End of Member Functions */
/* Overloaded Operators */
template <class T>
T& Array<T>::operator[](int index) {
/*if (index < 0 || index >= capacity)
cout << "Index out of range!" << endl;
else */
return arr[index];
}
template <class T>
ostream& operator<<(ostream &output, Array<T> &obj) {
for (int i = 0; i < obj.capacity - 1; ++i)
output << "Array[" << i << "] = " << obj[i] << ", ";
output << "Array[" << obj.capacity - 1 << "] = " << obj[obj.capacity - 1];
return output;
}
/* End of Overloaded Operators */
/* Non-member Functions */
template <typename T>
void BubbleSort(Array<T> &t);
template <typename T>
T Sum(Array<T> &t);
template <typename T>
T Average(Array<T> &t);
template <typename T, typename M>
bool Equal(Array<T> &t, Array<M> &m);
template <typename T>
bool Equal(Array<T> &t, Array<double> &d);
/* End of Non-Member Functions */
/* Main Function */
int main()
{
int n;
double r;
cin>>r;
cin>>n;
Array<int> anArray(n);
Array<double> adArray(n);
Array<int> intArray2(n);
for (int nCount = 0; nCount < n; nCount++)
{
cin>>anArray[nCount];
adArray[nCount] = anArray[nCount] + r;
}
BubbleSort(anArray);
intArray2 = anArray;
cout<<"The arrays: "<<endl;
cout<<anArray;
cout<<endl<<"and "<<endl;
cout<<intArray2;
cout<<((Equal(anArray,intArray2))?" ARE":" ARE NOT")<<" same!"<<endl;
cout<<"The Average of the array adArray is: "<<Average(adArray)<<endl;
cout<<"The arrays: "<<endl;
cout<<anArray;
cout<<endl<<"and "<<endl;
cout<<adArray;
cout<<((Equal(anArray,adArray))?" ARE":" ARE NOT")<<" same!";
return 0;
}
/* End of Main */
/* Non-Member Function implementation */
template <typename T>
void BubbleSort(Array<T> &t) {
int j;
bool flag = true;
while (flag) {
flag = false;
for (j = 0; j < t.GetLength() - 1; ++j) {
if (t[j] > t[j + 1]) {
swap(t[j], t[j + 1]);
flag = true;
}
}
}
return;
}
template <typename T>
T Sum(Array<T> &t) {
T sum = 0;
for (int i = 0; i < t.GetLength(); ++i)
sum += t.arr[i];
return sum;
}
template <typename T>
T Average(Array<T> &t) {
return ( Sum(t) / t.GetLength() );
}
template <typename T, typename M>
bool Equal(Array<T> &t, Array<M> &m) {
if ( t.GetLength() != m.GetLength() )
return false;
bool flag = true;
for (int i = 0; i < t.GetLength(); ++i) {
if ( t.arr[i] != m.arr[i] ) {
flag = false;
break;
}
}
return flag;
}
template <typename T>
bool Equal(Array<T> &t, Array<double> &d) {
if ( t.GetLength() != d.GetLength())
return false;
bool flag = true;
for (int i = 0; i < t.GetLength(); ++i) {
if ( abs(t.arr[i] - d.arr[i]) > 0.1 ) {
flag = false;
break;
}
if ( abs(Average(t) - Average(d)) > 0.5 ) {
flag = false;
break;
}
}
return flag;
}
/* End of Non-Member Function Implementation */
When i run this program in Code Blocks, there is no error and it produces the desired output. However, when I use it on our college's browser platform for writing programs (something like CodeSculptor for C++), after the desired output, it gives the following error:
***glibc detected*** double free or corruption (fasttop)
and then proceeds with a Memory map (it's quite long, so I'm not sure if I should post it or not).
My question is, if there is a problem with the code, then why doesn't it show when I run the program in CodeBlocks? In that case, what is the problem with the code? Also, when running the program in the browser platform, the error message is after the desired output. Does this mean there is something wrong with the program termination?
Thank you for your time.
You aren't implementing the rule of three.
This line intArray2 = anArray;, as you haven't provided the copy assignment operator, will use the built-in one, which will blindly copy each member of your object.
Now two object's T *arr point to the same place, and when the destructors gets called.. well, you get the idea... UB. glibc is really your friend here.
It also caused a memory leak (the previous arr pointer was simply overwritten), but compared to the double-freeing, that's a minor issue.
I have a class that takes the in an array and its size. in the class I have an index operator "[]" that has been overloaded to pass in its contents to a class member function and return that function. It also checks if I am accessing contents out side of the array size.
this_type operator[] (int index)
{
assert (index > 0 && index<=len);
at(index);
return c_arr()[index];
}
I made a copy constructor for it
//constructor
my_array(this_type const arr[], int size)
{
len = size;
assert(arr != NULL);
assert(size >= 0);
this->arr = new this_type[size];
for (int i = 0; i < size; i++)
(*this).arr[i] = arr[i];
}
//copy constructor
my_array( const my_array<this_type> & arr)
{
this->arr = new this_type[sizeof(arr)];
memcpy(this->arr, arr.arr, sizeof(this_type)*arr.len);
}
my_array(int size)
{
len = size;
assert(size >= 0);
this->arr = new this_type[size];
}
But it does not seem to pass in the array size value when called to the member function "len". Any thoughts?
#include <iostream>
#include <cassert>
#include <assert.h>
using namespace std;
template <class this_type>
class my_array
{
private:
this_type *arr;
int len;
int sum()
{
int sum;
for (int i = 0; i < len; i++)
sum += arr[i];
}
public:
int size() const
{
return len;
}
this_type &at(int index)
{
assert( index >= 0 && index < len);
return arr[index];
}
my_array(this_type const arr[], int size)
{
len = size;
assert(arr != NULL);
assert(size >= 0);
this->arr = new this_type[size];
for (int i = 0; i < size; i++)
(*this).arr[i] = arr[i];
}
my_array( const my_array<this_type> & arr)
{
this->arr = new this_type[sizeof(arr)];
memcpy(this->arr, arr.arr, sizeof(this_type)*arr.len);
}
my_array(int size)
{
len = size;
assert(size >= 0);
this->arr = new this_type[size];
}
~my_array()
{
delete[] arr;
}
this_type* c_arr()
{
return arr;
}
this_type & operator[] (int index)
{
assert (index > 0 && index<=len);
at(index);
return c_arr()[index];
}
this_type operator[] (int index)
{
assert (index > 0 && index<=len);
at(index);
return c_arr()[index];
}
friend istream & operator>>(istream &lhs, my_array<this_type> &rhs);
friend ostream & operator<<(ostream &lhs, my_array<this_type> &rhs);
};
template <class this_type>
ostream & operator<<(ostream &lhs, my_array<this_type>&rhs)
{
for ( int i = 0; i < rhs.size(); i++)
lhs << rhs.arr[i] << endl;
return lhs;
}
template <class this_type>
istream & operator>>(istream &lhs, my_array<this_type> &rhs)
{
for ( int i = 0; i < rhs.size(); i++)
lhs >> rhs.arr[i];
return lhs;
}
int main()
{
char arra[5]={'c','o','d','e','s'};
my_array<char> arr(arra,5), arr1(5), arr2(arr);
for(int t=0;t< 9;t++)
{
//use the operator that is attached to the class instance
cout << arr2[t];
}
for(int t=0;t< 9;t++)
{
cout<<arr2.c_arr()[t];
}
return 0;
}
this->arr = new this_type[sizeof(arr)];
This line from your copy constructor is not correct. arr is an object of your my_array class. sizeof(arr) is a compile time constant, and completely independent of the number of elements allocated for the array. Those elements are not even contained in the class. They are on the free store, and the class holds a pointer to them. What you want instead is this:
this->arr = new this_type[arr.len];
You also want to assign to the len member of the object you are constructing.
this->len = arr.len;
I am obliged to say that, unless you are creating this class for learning purposes, just use std::vector.
I have the template class and array of pointers to objects and overloaded logic operators for my objects. My bubble sort is working. So it's know how to compare my objects
I want to replace it with standard sort
Declaration
Implementation List.tem
#include <stdio.h>
#include <stdlib.h>
#include <vector>
///////////////
#include <iostream>
#include <fstream>
#include <algorithm>
using namespace std;
template <class Type>
List<Type>::List()
{
itemPtr = NULL;
used = 0;
size = 0;
}
template <class Type>
List<Type>::List(const List<Type>& source)
{
itemPtr = NULL;
used = 0;
size = source.size;
itemPtr = new Type[size];
for(int i = 0; i < source.used; i++)
addItem(source.itemPtr[i]);
}
template <class Type>
List<Type>& List<Type>::operator = (const List<Type>& source)
{
used = 0;
if(this == &source)
return(*this);
free();
size = source.size;
itemPtr = new Type[size];
for(int i = 0; i < source.used; i++)
addItem(source.itemPtr[i]);
return(*this);
}
template <class Type>
List<Type>::~List()
{
free();
}
template <class Type>
void List<Type>::free()
{
if(itemPtr != NULL)
{
delete [] itemPtr;
itemPtr = NULL;
}
}
template <class Type>
void List<Type>::alloc(int sizeIcrease)
{
Type* tmpPtr = NULL;
size += sizeIcrease;
tmpPtr = new Type[size];
copy(itemPtr, itemPtr+used, tmpPtr);
free();
itemPtr = tmpPtr;
}
template <class Type>
Type List<Type>::getItem(int index) const
{
Type item;
if(index >= 0 && index < used)
item = itemPtr[index];
return (item);
}
template <class Type>
int List<Type>::findItem(Type itemIn)
{
int i = 0;
for(i = 0; i < used; i++)
if(itemPtr[i] == itemIn)
break;
if (i == used) i = -1;
return (i);
}
template <class Type>
void List<Type>::addItem(Type itemIn)
{
if(used == size) alloc(10);
itemPtr[used++] = itemIn;
bubbles();
}
template <class Type>
void List<Type>::removeItem(Type itemIn)
{
int index = findItem(itemIn);
removeItem(index);
}
template <class Type>
void List<Type>::removeItem(int index)
{
if(index >= 0 && index < used)
itemPtr[index] = itemPtr[--used];
bubbles();
}
template <class Type>
void List<Type>::readFile(Field fileName)
{
Type itemTmp;
ifstream inFile(fileName.c_str());
if(!inFile)
cout << "Error opening file\n";
do
{
inFile >> itemTmp;
if(!inFile.fail())
addItem(itemTmp);
} while (!inFile.fail());
//bubbles();
vector<Type*> myvector; //(itemPtr, itemPtr+used);
vector<Type>::iterator it;
sort (myvector.begin(), myvector.end(), sort_by_pointee<Type>());
inFile.close();
}
template <class Type>
void List<Type>::writeFile(Field fileName)
{
ofstream outFile;
outFile.open(fileName.c_str());
if(!outFile)
cout << "Error opening file\n";
for(int i = 0; i < used; i++)
{
outFile << itemPtr[i] << "\n";
}
outFile.close();
}
template <class Type>
void List<Type>::print()
{
//////Coded
}
template <class Type>
void List<Type>::bubbles()
{
////// Coded
}
template <class Type>
ostream& operator<<(ostream& os, const List<Type>& ad)
{
for(int i = 0; i < ab.used; i++)
os << ab.getItem(i) << endl;
return os;
}
template <class Type>
ofstream& operator<<(ofstream& ofs, const List<Type>& ad)
{
for(int i = 0; i < ab.used; i++)
ofs << ab.getItem(i) << ",";
return ofs;
}
template<class Type>
struct sort_by_pointee
{
bool operator() (const Type* lhs, const Type* rhs) const
{
return (*lhs < *rhs);
}
};
If the third argument to std::sort() is not provided, objects are sorted using operator< like:
if (a < b) {
// ...
}
So all you need to sort objects of type Foo is to have either:
bool Foo::operator< (const Foo& rhs) const;
or
bool operator< (const Foo& lhs, const Foo& rhs);
That being said, if you have an array of pointers, then you will need to provide a custom predicate unless you want to sort objects by their memory address (I highly doubt this is what you want). You can do something like:
template<class T>
struct sort_by_pointee {
bool operator() (const T* lhs, const T* rhs) const
{
return (*lhs < *rhs);
}
};
And use it like:
std::vector<Foo*> foos;
// ...
std::sort(foos.begin(), foos.end(), sort_by_pointee<Foo>());
Edit: the sample you posted will work fine and sort the data, but the vector does not act as a proxy for the data stored in the itemPtr array. Read it again with my annotations:
{
vector<Type> myvector (itemPtr, itemPtr+8);
// 'myvector' holds a copy of the first 8 elements in the 'itemPtr' array.
sort (myvector.begin(), myvector.end());
// contents of 'myvector' are sorted, but this is a copy of 'itemPtr''s
// contents, so items in 'itemPtr' are still in their original order.
}
If you want to sort the contents of [itemPtr,itemPtr+8) in-place, you can just do:
std::sort(itemPtr, itemPtr+8); // use custom predicate if required.
Edit: OK, following the code you posted, I would fix the readFile() method from its original definition to:
template <class Type>
void List<Type>::readFile(Field path)
{
ifstream file(path.c_str());
if(!file.is_open()) {
cout << "Error opening file\n";
}
for (Type item; file >> item;) {
addItem(item);
}
sort (itemPtr, itemPtr+used);
}