Iam currently working on an assignment wherein;
I have to create my own array and array exception class.
SetElement(int arg) and GetElement(int arg) part of Array class, need to account for out of bound exceptions by throwing OutOfBoundsExcpetoinObject(Derrived) part of the Array Exception class (Base).,
I have to catch the Array Exception (base class).
I am getting an error that the abstract class cannot be caught.
These are the parameters. I have followed them, however i am still getting the abstract class cannot be caught error.
1.Give the ArrayException an abstract GetMessage() function that returns a std::string.
2.Give the OutOfBoundsException class a constructor with an int as argument that indicates the erroneous array index and store it in a data member.
3.Override the GetMessage() function and let the implementation return a message string saying the given index is out of bounds.
4.In the Array class, throw now a OutOfBoundsException object instead of an integer.
5.Change the main program so that it catches the ArrayException base class and uses the GetMessage() function to display an error message.
Main Function:
// creating an array
Array abc =Array(5);
Point* q = new Point(1,2);
//testing out of bounds cases in both get and set
abc.setElement(10,*q);
cout << abc.getElement(10);
ArrayException Class:
class ArrayException
{
private:
public:
ArrayException();
virtual string GetMessage() const=0;
};
class OutofBoundsException : public ArrayException
{
private:
int m_index;
public:
OutofBoundsException();
OutofBoundsException(int index);
virtual string GetMessage() const;
};
Array Class:
Array::Array():m_size(3),m_data(new CAD::Point[m_size]) {}
Array::Array(int size): m_size(size), m_data(new CAD::Point[m_size]) {}
Array::~Array()
{
delete[] m_data;
cout << "Destructor called" << endl;
}
Array::Array(const Array &obj) {
m_size = obj.m_size;
m_data = new CAD::Point[m_size];
for (int i = 0; i < m_size; i++)
{
m_data[i] = obj.operator[](i);
}
}
int Array::Size()
{
return m_size;
}
udbhavAg::CAD::Point &Array::getElement(int index)
{
try
{
if (index >= m_size || index < 0)
{
OutofBoundsException error = OutofBoundsException(index);
throw (error);
}
else
{
return m_data[index];
}
}
catch (ArrayException abc)
{
cout << abc.GetMessage();
}
}
void Array::setElement(int index, udbhavAg::CAD::Point p)
{
try
{
if (index >= m_size || index < 0)
{
OutofBoundsException error = OutofBoundsException(index);
throw (error);
}
else
{
m_data[index] = p;
}
}
catch (ArrayException error)
{
cout << error.GetMessage();
}
}
Array Array::operator=(const Array &source)
{
if (this == &source)
{
return *this;
}
m_data = source.m_data;
m_size = source.m_size;
return *this;
}
CAD::Point &Array::operator[](int index) {
return m_data[index];
}
const CAD::Point &Array::operator[](int index) const {
return m_data[index];
}
You should catch by reference to base, which can bind to a derived object:
catch (ArrayException const& abc)
Then just throw OutofBoundsException(index) directly,
I solved the error using referecnig and dereferencing. Since an instance of abstract class cannot be created it cannot be caught. However, an abstract class pointer can be created, hence i figured it can be caught.
I changed the code in my setElement & GetElement to the following and it works now:
udbhavAg::CAD::Point &Array::getElement(int index)
{
try
{
if (index >= m_size || index < 0)
{
OutofBoundsException error = OutofBoundsException(index);
ArrayException& abc = error;
throw (&abc);
}
else
{
return m_data[index];
}
}
catch (ArrayException *error)
{
cout << error->GetMessage();
}
}
void Array::setElement(int index, udbhavAg::CAD::Point p)
{
try
{
if (index >= m_size || index < 0)
{
OutofBoundsException error = OutofBoundsException(index);
ArrayException& abc = error;
throw (&abc);
}
else
{
m_data[index] = p;
}
}
catch (ArrayException *error)
{
cout << error->GetMessage();
}
}
Related
I need my front method to be able to support doing something like this for my assignment. Its been 4 hours. I can't seem to figure it out. I've tried overloading the = operator but that doesn't seem to work.
vectD3.front() = '{';
vectD3.back() = '}';
basically I need that code to not throw an error when ran
here is my front and back methods
public:T front()
{
if(currentSize > 0)
{
return array[0];
}
else
{
throw std::runtime_error("dynarray has no members");
}
}
public:T back()
{
if(currentSize > 0)
{
return array[currentSize-1];
}
else
{
throw std::runtime_error("dynarray has no members");
}
}
Thanks is advance
You need to return reference by your getter function. then you can modify it.
Something like this :
class A
{
public:
A(char d1): data(d1) {}
char& getData()
{
return data;
}
private:
char data;
};
int main()
{
A a('a');
std::cout << a.getData();//data = a
a.getData() = 'b';
std::cout << a.getData();//data = b
return 0;
}
for (int i = peekIndex; i < pdp->size(); i++)
{
string x = pdp->peek();
if (x.at(0) == 's')
{
out << pdp->peek() << endl;
pdp->moveForward();
}
else
{
pdp->moveForward();
}
}
The error I get is
terminate called after throwing and instance of std::out_of_range
what(): basic_string::at()
Abort
The peek method returns a string in the position of the peekIndex.
The moveFowrard method increments the peekIndex.
pdp is a vector of size 100. I am supposed to peek and print only words that start with 's' that have been pushed to the <vector>. I am basically done but this part is proving somewhat difficult.
Thanks
#include<iostream>
#include<vector>
#include<string>
using namespace std;
class StringDeque {
protected:
vector<string>* elements;
int frontItem; //CLASS INV: indexes item with least index
int rearSpace; //CLASS INV: indexes space after item with greatest index
int upperBound; //For array[0..n-1] this is "n" not "n-1".
public:
StringDeque(int guaranteedCapacity):
elements (new vector<string>( 2*guaranteedCapacity))
frontItem (guaranteedCapacity),
rearSpace ( guaranteedCapacity),
upperBound ( 2*guaranteedCapacity)
{}
proteted:
virtual bool isEmpty() const { return frontItem == rearSpace; }
virtual bool isFull() const { return rearSpace == upperBound || frontItem == 0; }
virtual int size() const { return rearSpace - frontItem; }
virtual string popRear() {
if (isEmpty()) {
cerr<< "Later we'll define and throw an EmptyQException"<< endl;
return "";
} else {
return elements->at(--rearSpace);
}
}
virtual string popFront() {
if (isEmpty()) {
cerr<<"Later we'll define and throw an EmptyQException"<<endl;
return "";
} else {
return elements->at(frontItem++);
}
}
/** Directions include similarly testing for "full" in the C++ code.
*/
virtual void pushFront(string newItem) {
elements->at(--frontItem)= newItem;
}
virtual void pushRear(string newItem) {
elements->at(rearSpace++) = newItem;
}
virtual string toString() {
string out = "";
for (int i = frontItem; i < rearSpace; i++) {
out += elements->at(i) + " ";
}
return out;
}
};
class PeekDeque : public StringDeque {
private:
int peekIndex;
public:
PeekDeque(int guaranteedCapacity):
StringDeque(guaranteedCapacity),
peekIndex(guaranteedCapacity/2)
{}
virtual void moveFrontward() {
if (peekIndex == upperBound) {
cerr<<"Cannot move past total capacity"<<endl;
} else{
elements->at(peekIndex ++);
}
}
virtual void moveRearward () {
if (peekIndex == -1) {
cerr<<"Cannot move below total capacity"<<endl;
} else{
elements ->at( peekIndex--);
}
}
virtual string popFront() {
cerr<<"Attempt to pop from empty PeekDeque"<<endl;
}
virtual string popRear() {
cerr<<"Attempt to pop from empty PeekDeque"<<endl;
}
virtual string peek() {
if (isEmpty()) {
cerr<<"Cannot peek an Empty index"<<endl;
return "";
} else {
return elements->at(peekIndex + 1);
}
}
virtual string toString() {
string out = "";
for (int i = frontItem; i < rearSpace; i++) {
out += elements->at(i) + " ";
}
return out;
}
};
int main(){
PeekDeque* pdp = new PeekDeque(101);
pdp->pushFront("oh");
pdp->pushFront("say");
pdp->pushFront("can");
pdp->pushFront("you");
pdp->pushFront("see");
pdp->pushRear("any");
pdp->pushRear("bad bugs");
pdp->pushRear("on");
pdp->pushRear("me?");
for(int i = peekIndex; i<pdp->size(); i++){
string x =
if(x.at(0)=='s'){
cout<<pdp->peek()<<endl;
pdp->moveForward(); }
else{
pdp->moveForward();
}
}
}
May be your test should be:
if(!x.empty() && x.at(0)=='s')
I can't tell exactly, without seeing more context, but I'm pretty sure x.empty() is a probable case.
UPDATE:
pdp is a vector of size 100
Are you sure to have used the pdp.resize(100,std::string()); method to ensure all positions are initialized correctly?
it is not empty i have pushed 8 things to pdp
Also std::vector<>::resize() and std::vector<>::push_back() might not work together as you expect. Use either std::vector<>::push_back() or std::vector<>::resize() to give it a pre-allocated size and manipulate entries by index. Always check for std::vector<>::size() for indexed access.
UPDATE 2:
But the real answer is apparently simpler. You have:
virtual string peek() {
if (isEmpty()) {
cerr<<"Cannot peek an Empty index"<<endl;
return ""; // This will certainly result in a string that is empty!
Here's how your container looks like after initial pushes:
0 202
| ... | ... | ... | ... |
^ ^ ^
| | rearSpace
| peekIndex
frontItem
Now, size() returns rearSpace - frontItem, but iteration starts from peekIndex and thus goes beyond rearSpace index, peeking uninitialized (empty) strings.
That's certainly an approximate answer, since your work with indices is a mess. Please be really careful and think it through.
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.
This is my first pathetic attempt at C++. I did an array based stack in C++ and the destructor is throwing out some memory dump. I can't figure out what went wrong.
#include <stdio.h>
#include <iostream>
#include <exception>
using namespace std;
class FullStackException : public exception {
virtual const char* what() const throw() {
return "Stack is full.";
}
} fsex;
class EmptyStackException : public exception {
virtual const char* what() const throw() {
return "Stack is empty.";
}
} esex;
template <class D>
class ArrayBasedStack {
private:
int t; //t represents top
D *S;
int arrSize;
public:
ArrayBasedStack(int arraySize = 10);
~ArrayBasedStack();
int size(); /*returns the number of elements stored*/
void push(D&); /*inserts an element*/
D pop(); /*removes and returns the last inserted element*/
D top(); /*returns the last inserted element without removing it*/
int isEmpty(); /*indicates whether no elements are stored*/
};
template <class D>
ArrayBasedStack<D>::ArrayBasedStack(int arraySize) {
/* Elements are added from left to right */
S = new D[arraySize];
arrSize = arraySize;
/* t keeps track of the index of the top element */
t = -1;
}
template <class D>
ArrayBasedStack<D>::~ArrayBasedStack() {
if(S != NULL) {
int i = 0;
for(i = 0; i < size(); i++) {
S[i] = NULL;
}
cout << "about to delete S" << endl;
delete[] S;
}
}
template <class D>
int ArrayBasedStack<D>::size() {
return t;
}
template <class D>
void ArrayBasedStack<D>::push(D& data) {
if(t == arrSize) {
throw fsex;
} else {
S[t] = data;
t++;
}
}
template <class D>
D ArrayBasedStack<D>::pop() {
if(isEmpty()) {
throw esex;
}
D element = S[t];
S[t--] = NULL;
return element;
}
/*
* returns true if the stack is empty, false otherwise
*/
template <class D>
int ArrayBasedStack<D>::isEmpty() {
return (t < 0);
}
int main(int argc, char *argv[]) {
char inputs[][10] = {
"str1"
};
char *i = NULL;
ArrayBasedStack<char *> stack;
i = inputs[0];
stack.push(i);
try {
stack.pop();
}
catch(exception& ex) {
cout << "ERR:" << ex.what() << endl;
}
return 0;
}
The problem line is
t = -1;
Should be
t = 0;
because when you add first element, the following code is excecuted
} else {
S[t] = data; // t == -1
t++;
}
The following is the culprit.
template <class D>
void ArrayBasedStack<D>::push(D& data) {
if(t == arrSize) {
throw fsex;
} else {
S[t] = data; // Should be S[++t] = data;
t++; // Comment out this line
}
}
This implemntation assumes that 't' points to the topmost element on the stack rather than to the next available location for push
Note that operator [] and operator ++ have same precedence. Since they associate left-to-right, [] is evaluated before operator ++.
In your implementation, here is the problem. With t being initialized to -1, you are overwriting beyond the array subscript that is at S[-1] which leads to undefined behavior.
At least on my system the problem surfaces while trying to free the memory in destructor of the stack class. This is a classic example of a syptom being visible much after the goof-up has happened
Also would suggest push to take the parameters as D const &
I need to implement a dynamic array by myself to use it in a simple memory manager.
struct Block {
int* offset;
bool used;
int size;
Block(int* off=NULL, bool isUsed=false, int sz=0): offset(off), used(isUsed), size(sz) {}
Block(const Block& b): offset(b.offset), used(b.used), size(b.size) {}
};
class BlockList {
Block* first;
int size;
public:
BlockList(): first(NULL), size(0) {}
void PushBack(const Block&);
void DeleteBack();
void PushMiddle(int, const Block&);
void DeleteMiddle(int);
int Size() const { return size; }
void show();
Block& operator[](int);
Block* GetElem(int);
void SetElem(int, const Block&);
~BlockList();
};
I need to overload operator[].
Block& BlockList::operator\[\](int index) {
try {
if (index >= size)
throw out_of_range("index out of range");
else
return (first[sizeof(Block)*index]);
}
catch(exception& e) {
cerr << e.what() << endl;
}
}
void BlockList::PushBack(const Block& b) {
if(!size)
first = new Block(b);
else {
Block* temp = new Block[size + 1];
int i = 0;
for (i = 0; i < size; i++)
temp[sizeof(Block)*i] = this->operator[](i);
delete []first;
temp += sizeof(Block);
temp->offset = b.offset;
temp->size = b.size;
temp->used = b.used;
first = temp;
}
size++;
}
When I use PushBack to push the first element, it works OK, but when it comes to the second, third, ..., the program didn't crash, but it just shows results I didn`t expect to see.
Here is how I get the contents of my array:
void BlockList::show() {
for (int i = 0; i < size; i++) {
Block current(operator[](i));
cout << "off: " << current.offset << " size: " << current.size << endl;
}
}
first is a Block pointer so you only need to pass in index.
Block* first;
...
first[0] //returns the first element
first[1] //returns the second element
In your example you are passing in too high of an index value when indexing first because you're using sizeof inside.
Corrected code:
Block& BlockList::operator[](int index) {
try {
if (index >= size)
throw out_of_range("index out of range");
else
return (first[index]);//<--- fix was here
}
catch(exception& e) {
cerr << e.what() << endl;
}
}
An array knows how big its elements are, so you don't have to do the math with sizeof(Block). Just use i as the index.
On a related note, the C++ FAQ Lite has a great section on operator overloading that covers all kinds of useful stuff.