I have implemented a List (different from standard c++ list), this is for exercise.
The problema is that after resizing the list, I get segmentation fault.
I have marked the linke when I get seg. fault, I don't know the reason.
The purpose of resize method is to resize the list: let's say that I have a list of 2 integers, if I resize it to 5 I'll get other 3 elements, all initialized to zero.
If instead I have a list of 4 elements, and I resize it to 2, 2 elelements will be cut.
If I have a int list l, l[0] is the first object of the list, l[1] the second...
So I crash when i attempt to resize the list, exactly in the line that I have marked.
#include <iostream>
#include <cassert>
using namespace std;
template<class T>
class List
{
public:
List<T>();
~List<T>();
protected:
List<T> (T info);
public:
int size();
void resize(int length);
void add(T info,int i);
void push(T info);
T pop();
void remove(int i);
T extract(int i);
T get(int i);
friend ostream& operator<< (ostream& out, List<T>& l)
{
List<T>* ptr=l.next;
if(l.info==NULL)
{
while(ptr!=&l)
{
out << *(ptr->info) << "\t";
ptr=ptr->next;
}
}
else
{
out<< *(l.info) <<"\t";
}
return out;
}
friend istream& operator>> (istream& in,List<T>& l)
{
in >> (*l.info);
return in;
}
bool operator== (List<T>& r)
{
bool result=true;
List<T>* p1,*p2;
p1=this;
p2=&r;
assert((p1->info==NULL && p2->info==NULL)||(p1->info!=NULL && p2->info!=NULL));
if(p1->info==NULL)
{
p1=p1->next;
p2=p2->next;
result=(p1->length == p2->length);
while(result && p1!=this)
{
result=(*(p1->info)==*(p2->info));
p1=p1->next;
p2=p2->next;
}
}
else
{
result=(*(p1->info)==*(p2->info));
}
return result;
}
List<T>& operator+= (List<T>& l)
{
List<T>* ptr;
ptr=l.next;
while(ptr!=&l)
{
this->push(*(ptr->info));
ptr=ptr->next;
}
return *this;
}
List<T>& operator[] (int i)
{
List<T>* ptr;
ptr=this;
assert(i<length);
for(int j=0;j<=i;j++)
ptr=ptr->next;
return *ptr;
}
private:
T *info;
List <T>* next;
List <T>* prev;
int length;
};
template <class T>
List<T>::List ()
{
info=NULL;
next=this;
prev=this;
length=0;
}
template<class T>
List<T>::List (T info)
{
next=this;
prev=this;
this->info=new T();
*(this->info)=info;
}
template<class T>
List<T>::~List()
{
List<T>* ptr, * temp;
ptr=this->next;
if(this->info==NULL)
{
while(ptr!=this)
{
delete ptr->info;
temp=ptr;
ptr=ptr->next;
delete temp;
}
}
}
template<class T>
int List<T>::size()
{
return length;
}
template<class T>
void List<T>::resize(int length)
{
assert(length>=0);
if(this->length<length)
{
for(int i=this->length;i<length;i++)
push(0);
}
else
{
for(int i=length;i<this->length;i++)
extract(this->length-1); // here I call exctract, extract calls
} // remove, remove calls get
}
template<class T>
void List<T>::add(T info,int i)
{
List<T>* ptr,*t1,*t2;
length++;
ptr=&((*this)[i]);
t1=ptr->prev;
t2=ptr;
ptr=new List<T>(info);
t1->next=ptr;
ptr->prev=t1;
t2->prev=ptr;
ptr->next=t2;
}
template<class T>
void List<T>::push(T info)
{
add(info,length-1);
}
template<class T>
void List<T>::remove(int i)
{
List<T>* ptr,*t1,*t2;
ptr=&((*this)[i]);
t1=ptr->prev;
t2=ptr->next;
delete ptr;
t1->next=t2;
t2->prev=t1;
length--;
}
template<class T>
T List<T>::extract(int i)
{
T temp=this->get(i);
remove(i);
return temp;
}
template<class T>
T List<T>::get(int i)
{
assert(i<length);
return *(this[i].info); // here i have seg. fault !!!!!!!!!!
} // I cannot figure why ...
template<class T>
T List<T>::pop()
{
return extract(length-1);
}
int main(int argc, char **argv)
{
List<int> l;
l.resize(3);
for(int i=0;i<3;i++)
cin>>l[i];
l.resize(2);
cout<<l<<endl;
return 0;
}
I hope it's not a too kilometric doce, thanks in advance for who will read and try to help me.
In resize, the for loops change i and compare it with this->length, but both push and extract change this->length, so you're comparing two changing variables against each other.
This may be better a better approach:
while(this->length < length)
push(0);
Related
I am trying to make a sorting function for a ring buffer class object, but it gives me the below error and I couldn't remove it:
template placeholder type 'ring' must be followed by a simple declarator-id
argument list for class template "ring" is missing
'arr' was not declared in this scope
(arr) was declared in the parameter of the function but yet it does not recognize it
hopefully someone can explain what is wrong with the sorting function, here is below my code:
#include<iostream>
#include<initializer_list>
template<typename T>
void swap(T& x, T& y) {
T temp;
temp = x;
x = y;
y = temp;
}
template<typename T>
class ring {
public:
class iterator;
public:
ring(std::initializer_list<T>elements) {
sze = elements.size();
value = new T[sze];
for (auto& i : elements) {
add(i);
}
}
T& get(int x) { return value[x]; }
std::size_t size() { return sze; }
void add(T v) {
value[index++] = v;
if (index == sze)
index = 0;
}
iterator begin() { return iterator(0, *this); }
iterator end() { return iterator(sze, *this); }
friend void BubbleSort(ring& arr, std::size_t n);
~ring() { delete[] value; }
private:
int index = 0;
std::size_t sze;
T* value;
};
template<typename T>
class ring<T>::iterator {
public:
iterator(int x, ring& y) :index(x), obj(y) {}
iterator& operator++() { index++; return *this; }
iterator& operator++(int x) { index++; return *this; }
bool operator!=(const iterator& other) { return index != other.index; }
T& operator*() { return obj.get(index); }
private:
int index;
ring& obj;
};
template<typename T>
void BubbleSort(ring& arr, std::size_t n) { // here is the function of the sorting.
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (arr.value[j] > arr.value[j + 1]) {
swap(arr.value[j], arr.value[j + 1]);
}
}
}
}
Your friendly compiler showed you already the problem and in which line it happened.
And it gave you 3 error messages telling you exactly what the problem is.
See my compiler output
Your class ring needs a template parameter. So same as in line 49 of the picture.
The below will compile.
#include<iostream>
#include<initializer_list>
template<typename T>
void swap(T& x, T& y) {
T temp;
temp = x;
x = y;
y = temp;
}
template<typename T>
class ring {
public:
class iterator;
public:
ring(std::initializer_list<T>elements) {
sze = elements.size();
value = new T[sze];
for (auto& i : elements) {
add(i);
}
}
T& get(int x) { return value[x]; }
std::size_t size() { return sze; }
void add(T v) {
value[index++] = v;
if (index == sze)
index = 0;
}
iterator begin() { return iterator(0, *this); }
iterator end() { return iterator(sze, *this); }
friend void BubbleSort(ring& arr, std::size_t n);
~ring() { delete[] value; }
private:
int index = 0;
std::size_t sze;
T* value;
};
template<typename T>
class ring<T>::iterator {
public:
iterator(int x, ring& y) :index(x), obj(y) {}
iterator& operator++() { index++; return *this; }
iterator& operator++(int x) { index++; return *this; }
bool operator!=(const iterator& other) { return index != other.index; }
T& operator*() { return obj.get(index); }
private:
int index;
ring& obj;
};
template<typename T>
void BubbleSort(ring<T>& arr, std::size_t n) { // here is the function of the sorting.
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (arr.value[j] > arr.value[j + 1]) {
swap(arr.value[j], arr.value[j + 1]);
}
}
}
}
I did not check the functionality. Sorting a ringbuffer sounds somehow strange . . .
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.
Im trying to resize my stack but my program keeps terminating after the 'cout'.
On the output terminal it displays 1 and then the program terminates. In this case T is an int and size is set to 10 by default. Any help will be much appreciated.
#include <iostream>
#include <fstream>
using namespace std;
template <typename T>
class stack {
public:
int topStack;
T* stack1;
int size;
void copy(const stack& other);
void move(stack&& other);
// constructor
stack ();
// destructor
~stack()
{
delete[] stack1;
};
// copy constructor
stack (const stack&);
// copy assignment
stack& operator= (const stack&);
// move constructor
stack (stack&&);
// move assignment
stack& operator= (stack&&);
T& top() const; // return the top element
void pop (); // remove the top element
void push(const T&); // add element on top of stack
void push (T&&); // add element on top of stack
bool empty() const; // is the stack empty?
void clear(); // remove all elements
ostream& print(ostream&, stack&);
void resize();
};
//Default Constructor
template <typename T>
stack<T>::stack()
{
size=10;
stack1= new T[size];
for(int b =0; b < size; b ++)
{
stack1[b] = T();
}
topStack =-1;
}
//Copy Constructor
template <typename T>
void stack<T>::copy(const stack& other)
{
topStack = other.topStack;
stack1= new T[other.size];
size =other.size;
for(int i=0; i< other.size ; i++)
{
stack1[i]=other.stack1[i];
}
}
//Copy assignment
template <typename T>
stack<T>& stack<T>::operator =(const stack& other)
{
if (this == &other) return *this;
T* store = new T[other.size];
for(int g =0; g < other.size ; g++)
{
store[g]= other.stack1[g];
}
delete[] stack1;
this->stack1 = store;
this->size = other.size;
this-> topStack = other.topStack;
return *this;
}
//Move Constructor
template<typename T>
void stack<T>::move(stack && other)
{
topStack = other.topStack;
other.topStack = 0;
stack1 = other.stack1;
for(int u =0; u < other.size ; u++)
{
other.stack1[u]=0;
}
size = other.size;
other.size=0;
}
//Move assignment
template <typename T>
stack<T>& stack<T>::operator= (stack&& other)
{
this->size = other.size;
other.size=0;
this->topStack = other.topStack;
other.topStack=0;
this->stack1 = other.stack1;
for(int u =0; u < this->size ; u++)
{
other.stack1[u]=0;
}
return *this;
}
//Checks if stack is empty
template <typename T>
bool stack<T>::empty() const
{
return topStack == -1;
}
//Resize array
template<typename T>
void stack<T>::resize()
{
cout << "DAYYYY55UM";
T* storage = new T[this->size*2];
cout << "DAYYYYUM";
for(int r=0; r < this->size ; r++)
{
storage[r]= this->stack1[r];
}
delete[] this->stack1;
this->stack1= storage;
this->size = size*2;
cout << "DAYYYYUM";
}
//Returns top
template <typename T>
T& stack<T>::top() const
{
if(empty())
{
cout << "ERROR: Stack is empty. "<< endl;
return;
//Make a throw catch statement here
}
return stack1[topStack];
}
//Pop
template <typename T>
void stack<T>::pop()
{
if(empty())
{
cout << "ERROR: Stack is empty." << endl;
return;
}
stack1[topStack] =0;
topStack--;
}
//Push
template <typename T>
void stack<T>::push(const T& q)
{
if(topStack < size)
{
topStack++;
stack1[topStack] = q;
}else{
resize();
}
}
//Push
template <typename T>
void stack<T>::push(T&& q)
{
if(topStack < size)
{
topStack++;
stack1[topStack] = q;
}else{
resize();
}
}
//Print Function
template <typename T>
ostream& stack<T>::print(ostream& os, stack& other)
{
os << other.stack1 ;
}
template <typename T>
void stack<T>::clear()
{
for(int g=0; g < size; g++ )
{
stack1[g]=0;
}
}
int main()
{
stack<int> world;
world.push(9);
world.push(40);
world.push(40);
world.push(9);
world.push(40);
world.push(40);
world.push(9);
world.push(40);
world.push(40);
world.push(9);
world.push(40);
world.push(40);
cout << world.stack1[12] << endl;
return 0;
}
That error means that you have an out of bounds array access somewhere that is corrupting malloc's data structures.
The error is in your push function:
template <typename T>
void stack<T>::push(T&& q)
{
if(topStack < size)
{
topStack++;
stack1[topStack] = q;
}else{
resize();
}
}
When you write the last item before resize, topStack is one less than size, which is a valid index (the last one, indeed), but then you increment it to size, and write the item in that position, and that's not a valid index.
By the way, you have a lot of errors with the indexes al over your class. My advice woulbe to take into account that c++ arrays start at 0 and end at size-1, and revise your code.
And have you noticed that when you resize the array you don't add the new item?
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);
}
My derived class merge_sort from dynamic_array does not have access to protected member T* array. Their are error everywhere it is used saying such.
I'm not sure why...except maybe the public designator for merge_sort should be something else?
#include "c_include.cpp"
using namespace std;
template <class T> class dynamic_array
{
protected:
T* array;
public:
int size;
void rorder();
void order();
void randorder();
void print_operator(ostream&)const;
dynamic_array(int sizein)
{
size=sizein;
array=new T[size]();
}
};
template <class T> void dynamic_array<T>::print_operator(ostream &os=cout)const
{
for (int i = 0; i < size; i++) os << array[i] << endl;
}
template <class T> void dynamic_array<T>::randorder()
{
srand(time(NULL));
int *ap;
for(ap=array;ap!=array+size;++ap){*ap=rand();}
}
template <class T> void dynamic_array<T>::order()
{
int *ap,i=0;
for(ap=array;ap!=array+size;++ap)
{
*ap=i;
++i;
}
}
template <class T> void dynamic_array<T>::rorder()
{
int *ap,i=size;
for(ap=array;ap!=array+size;++ap)
{
*ap=i;
--i;
}
}
template<class T> ostream& operator<<(ostream& stream, dynamic_array<T> const& data)
{
data.print_operator(stream);
return stream;
}
/*
Merge Sort
*/
template <class T> class merge_sort : public dynamic_array <T>
{
private:
const static int size;
int scratch[];
void flip_if_unordered(int &x, int &y)
{
if(array[x]>array[y])
{
int tmp=array[x];
array[x]=array[y];
array[y]=tmp;
}
}
void merge_algo(int &left, int &right_begin, int &right)
{
int iter,iter_left=left,iter_right=right_begin;
for(iter=left;iter<=right;++iter)
{
if( (iter_right>right) || ((iter_left < right_begin) && (array[iter_left]<=array[iter_right])))
{
scratch[iter]=array[iter_left];
++iter_left;
}
else
{
scratch[iter]=array[iter_right];
++iter_right;
}
}
for(iter=left;iter<=right;++iter){array[iter]=scratch[iter];}
}
void merge_recurse(int left,int right)
{
int left_end=(left+((right-left)/2));
int right_begin=left_end+1;
if(((left+1)==right)){flip_if_unordered(left,right);return;}
else if ((left==right)){return;}
else
{
merge_recurse(left,left_end);
merge_recurse(right_begin,right);
merge_algo(left,right_begin,right);
}
}
public:
merge_sort()
{
scratch = new T[size]();
if(scratch != NULL)
{
merge_recurse(0, size);
}
}
};
/*Quick Sort
void quick_sort()
{
quick_recurse(0,size);
}
void quick_recurse(int left, int right)
{
int l = left, r = right, tmp;
int pivot = array[(left + right) / 2];
while (l <= r)
{
while (array[l] < pivot)l++;
while (array[r] > pivot)r--;
if (l <= r)
{
tmp = array[l];
array[l] = array[r];
array[r] = tmp;
l++;
r--;
}
}
if (left < r)quick_recurse(left, r);
if (l < right)quick_recurse(l, right);
}
*/
Your base class depends on a template argument, so its type is a dependent type. The compiler won't know which specialization of the base class you use until is instantiated, so you have to help the compiler know that such identifier is a base's member. Either like this:
dynamic_array<T>::array
or
this->array
or
using dynamic_array<T>::array;