glibc error after desired output - c++

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.

Related

Problem freeing memory (subject Template)

Set.h
#ifndef Set_h
#define Set_h
#include <iostream>
using namespace::std;
template <class T>
class Set {
T* group;
int size_group;
public:
Set():group(NULL),size_group(0){};
Set(T*,int);
Set(const Set<T>&);
~Set();
bool isThere(const T&)const;
void getType()const;
Set<T>& operator =(const Set<T>&);
bool operator ==(const Set<T>&) const;
void operator +=(const T);
void operator -=(const T&);
Set<T>& operator +(Set<T>&);
Set<T>& operator -(const Set<T>&);
bool operator >(const Set<T>&)const;
friend ostream& operator <<(ostream&,const Set<T>&);
};
//Realizations
template <class T>
Set<T>::Set(T* gro,int size):group(gro),size_group(size){}
template <class T>
Set<T>::Set(const Set<T>& obj){ // c'Ctor (copy)
this->size_group = obj.size_group;
this->group = new T[this->size_group];
for (int i = 0; i < size_group; i++) {
group[i] = obj.group[i];
}
}
template <class T>
void Set<T>::getType() const{
cout << "The type is: " << typeid(group).name() << endl;
}
template <class T>
Set<T>& Set<T>::operator = (const Set<T>& obj){
this->size_group = obj.size_group;
this->group = new T[size_group];
for (int i = 0; i < size_group; i++) {
this->group[i] = obj.group[i];
}
return *this;
}
template <class T>
bool Set<T>::operator==(const Set<T>& obj) const{
int count = 0;
T temp;
if(this->size_group != obj.size_group)
return false;
for (int i = 0; this->size_group; i++) {
temp = this->group[i];
count = 0;
for (int j = 0; j < obj.size_group; j++) {
if(temp == obj.group[j])
count++;
}
if(count != 1)
return false;
}
return true;
}
template <class T>
void Set<T>::operator+=(const T var){
if(!isThere(var)){
T* Temp = new T[this->size_group+1];
for (int i = 0; i < this->size_group; i++)
Temp[i] = this->group[i];
Temp[size_group] = var;
delete [] this->group;
this->size_group++;
this->group = Temp;
}
}
template <class T>
Set<T>& Set<T>::operator+(Set<T>& obj){ //
if(obj.size_group > this->size_group){
for (int i = 0; i < obj.size_group; i++){
for (int j = 0 ; j < this->size_group; j++){
if(!this->isThere(obj.group[i]))
*this += obj.group[i];
}
}
return *this;
}else{
for (int i = 0; i < this->size_group; i++){
for (int j = 0 ; j < obj.size_group; j++){
if(!obj.isThere(this->group[i]))
obj += this->group[i];
}
}
return obj;
}
}
template <class T>
bool Set<T>::isThere(const T& var) const{
for (int i = 0; i < this->size_group; i++) {
if(this->group[i] == var)
return true;
}
return false;
}
template <class T>
Set<T>::~Set() {
delete [] group;
}
#endif /* Set_h */
Main:
#include "Set.h"
int main() {
int arr[] = {3,7,8,1};
int arr2[] = {1,2,5};
Set<int> j(arr,4),l(arr2,3),k;
k = j + l;
}
I'm trying to merge two arrays, but my problem is with the method void Set<T>::operator+=(const T var) and this line delete [] this-> group;
I get this error:
Template & Exception (8421,0x1000dadc0) malloc: *** error for object 0x7ffeefbff400: pointer being Friday was not allocated
Template & Exception (8421,0x1000dadc0) malloc: *** set a breakpoint in malloc_error_break to debug
Your Set(T*,int) constructor is not allocating new[]'ed memory for group to point at, which means operator+= (and ~Set(), and operator=) will fail at runtime when they try to delete[] the memory that group points at, which in your example is local stack memory that main() owns and passes in to the j and l objects.
Your Set(T*,int) constructor must new[] the group array and copy the contents of the input gro array into it, similar to how your copy constructor does, eg:
template <class T>
Set<T>::Set(T* gro, int size) : group(NULL), size_group(0)
{
size_group = size;
group = new T[size];
for (int i = 0; i < size; i++) {
group[i] = gro[i];
}
}
On a side note, your operator= is leaking memory, as it does not delete[] the current group array before assigning a new group array. It should be making a temporary array, similar to how your operator+= does, eg:
template <class T>
Set<T>& Set<T>::operator=(const Set<T>& obj)
{
if (this != &obj){
T* Temp = new T[obj.size_group];
for (int i = 0; i < obj.size_group; i++)
Temp[i] = obj.group[i];
delete [] group;
group = Temp;
size_group = obj.size_group;
}
return *this;
}
Or better, use your copy constructor via the copy-swap idiom instead:
template <class T>
Set<T>& Set<T>::operator=(const Set<T>& obj)
{
if (this != &obj){
Set<T> temp(obj);
std::swap(group, temp.group);
std::swap(size_group, temp.size_group);
}
return *this;
}
Also, your operator+ is implemented all wrong. It needs to return a new Set that is the concatenation of the arrays of *this and obj, not modify obj or *this at all. As such, it needs to look more like this instead:
template <class T>
Set<T> Set<T>::operator+(const Set<T>& obj) const
{
Set<T> res(*this);
for (int i = 0; i < obj.size_group; i++) {
res += obj.group[i];
}
return res;
}

Trying to convert base class to a class template

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

c++ - Calling template funсtion without <'typename'>

I'm creating doubly linked list which has different types with template.
here is header and main code.
#ifndef UNV_LIST
#define UNV_LIST
#include <typeinfo>
using namespace std;
class node_base{
public:
node_base *next;
node_base *prev;
node_base () { next = 0; prev = 0; }
virtual int get_node_size () = 0;
};
template <typename T>
class node : public node_base{
public:
T data;
node (const T& val) : data(val) {}
virtual int get_node_size () { return sizeof (data); }
T getData () { return data; }
};
class unvlist{
node_base *head;
public:
int len;
unvlist ();
template <typename T> unvlist (const T* arr, int n);
~unvlist ();
template <typename T> void set (int n, const T& val);
template <typename T> T get (int n);
template <typename T> T insert (int n, const T& val);
void erase (int n);
int size ();
void pop_back ();
void pop_front ();
template <typename T> void push_back (const T& val);
template <typename T> void push_front (const T& val);
};
unvlist :: unvlist (){
head = 0;
len = 0;
}
/* I want to use this function without <> */
template <typename T>
T unvlist :: get (int n){
T retval;
if (n >= len || n < 0){
cout << "'In unvlist::get'-> Out of Bound!!!" << endl;
return 0;
}
if (n >= 0){
node_base *h = head;
for (int i = 0; i < n; i++) { h = h->next; }
retval = static_cast<node<T>*>(h)->getData ();
cout << retval << endl;
}
return retval;
}
template <typename T>
void unvlist :: push_back (const T& val){
node_base *n = new node<T> (val);
if (head == NULL){
head = n;
len++;
}else{
node_base *h = head;
while (h->next != NULL) { h = h->next; }
h->next = n;
n->prev = h;
len++;
}
}
template <typename T>
void unvlist :: push_front (const T& val){
node_base *n = new node<T> (val);
if (head == NULL){
head = n;
len++;
}else{
head->prev = n;
n->next = head;
head = n;
len++;
}
}
#endif
and main.cpp
#include <iostream>
#include "unvlist.hpp"
using namespace std;
int main (){
unvlist *l1 = new unvlist ();
l1->push_back<string> ("aa");
l1->push_back<char> ('A');
l1->push_back<float> (1.2345);
l1->push_front<int> (11);
for (int i = 0; i < 4; i++){
cout << l1->get (i) << endl; //The problem is here...
} cout << endl;
return 0;
}
I have to use the template function 'T get(int n)' without explicit <>.
When I compiled it, however, there are some errors...
g++ -std=c++11 -Wall main.cpp -o main
main.cpp: In function 'int main()'
main.cpp:16:21: error: no matching function for call to 'unvlist::get(int&)'
cout << l1->get (i) << endl;
^
main.cpp:16:21: note: candidate is:
In file included from main.cpp:3:0:
unvlist.hpp:44:27: note: template<class T> T unvlist::get(int)
template <typename T> T get (int n);
^
unvlist.hpp:44:27: note: template argument deduction/substitution failed:
main.cpp:16:21: note: couldn't deduce template parameter 'T'
cout << l1->get (i) << endl;
^
make: *** [all] Error 1
'push_back' and 'push_front' function work well, but the problem is 'T get' function...
Is there a way to use 'T get' function without <>?
I have to use the template function 'T get(int n)' without explicit <>
Well, you can't.
No arguments have anything to do with T, so the compiler has no way of knowing what you want it to do. It cannot read your mind.
It is impossible to derive the type of the template parameter T for the function
T unvlist::get(int i)
having just such a call list->get(3).
You could modify your getter as follows:
template <typename T>
void unvlist :: get (int n, T &retval){
if (n >= len || n < 0){
cout << "'In unvlist::get'-> Out of Bound!!!" << endl;
}
if (n >= 0){
node_base *h = head;
for (int i = 0; i < n; i++) { h = h->next; }
retval = static_cast<node<T>*>(h)->getData ();
}
}
And use with a priory known resulting type:
int main (){
unvlist *l1 = new unvlist ();
l1->push_back<string> ("aa");
l1->push_back<string> ("A");
for (int i = 0; i < 2; i++){
std::string result; // we know std::string in advance
l1->get(i, result); // here compiler derives the T type correctly
std::cout << result << std::endl;
} cout << endl;
return 0;
}
In terms of answering strictly what you've asked, no; the complier needs to know which version of get you're trying to call.
However you can achieve what it seems you're trying to do.
If get were to return node_base by reference (or pointer), and node_base had a virtual operator>> that was overridden for each node then the type problem goes away.
If you consider the node_base class to be an implementation detail that shouldn't be exposed, then you could create another class for get to return instead (again a base class with type specific derived classes).

Adding to dynamic array

Disclaimer: Yes, I know about std::vector. I'm doing this for the sake of learning.
I'm working on making a dynamic array class, and I'm trying to get add to work.
template <class T>
void Array<T>::add(T value)
{
T * tmp = new T[mCount];
for (int i = 0; i < mCount; i++)
{
tmp[i] = mData[i];
}
mCount++;
delete[] mData;
mData = tmp;
mData[mCount - 1] = value;
}
It works... sort of. The function works in adding the element, but then the program crashes when exiting. No errors, no nothing. It just freezes, and I have to close it using (Shift + F5).
So, what's wrong with this?
Here's my whole class. If I didn't include a function it means there's no code in it.
#ifndef ARRAY_H
#define ARRAY_H
using namespace std;
template <class T>
class Array
{
private:
T * mData;
int mCount;
public:
Array();
~Array();
void add(T value);
void insert(T value, int index);
bool isEmpty();
void display();
bool remove(T value);
bool removeAt(int index);
int size();
T & operator[](const int index);
};
// Constructors / Destructors
// --------------------------------------------------------
template <class T>
Array<T>::Array()
{
mCount = 0;
mData = new T[mCount];
for (int i = 0; i < mCount; i++)
mData[i] = 0;
}
template <class T>
Array<T>::~Array()
{
delete[] mData;
}
// General Operations
// --------------------------------------------------------
template <class T>
void Array<T>::add(T value)
{
T * tmp = new T[mCount];
for (int i = 0; i < mCount; i++)
{
tmp[i] = mData[i];
}
mCount++;
delete[] mData;
mData = tmp;
mData[mCount - 1] = value;
}
template <class T>
void Array<T>::display()
{
if (isEmpty())
{
cout
<< "The array is empty."
<< "\n\n";
return;
}
cout << "(";
for (int i = 0; i < mCount; i++)
{
cout << mData[i];
if (i < mCount - 1)
cout << ", ";
}
cout << ")" << "\n\n";
}
template <class T>
bool Array<T>::isEmpty()
{
return mCount == 0;
}
template <class T>
int Array<T>::size()
{
return mCount;
}
// Operator Overloads
// --------------------------------------------------------
template <class T>
T & Array<T>::operator[](const int index)
{
return mData[index];
}
#endif
If you need any additional info lemme know and I can post it.
Assuming mCount keeps the number of elements in the array, then when adding a new element you really have to allocate at least mCount + 1 elements (assuming of course you want to keep all the old ones and the new one) via:
T * tmp = new T[mCount + 1];
as opposed to:
T * tmp = new T[mCount];
If it's for anything else other than educational purposes, please use std::vector instead. For example your add function is not exception safe.

C++ How to use std::sort to sort a array of objects in c++

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);
}