Class destructor, runtime error: Unhandled exception - Stack overflow - c++

The destructor for List appears to work, but having trouble with the destructor for Element and List_iter:
Unhandled exception : 0xC00000FD: Stack overflow (parameters: 0x00000001, 0x002E2F78).
List:
#ifndef GUARD_List_h
#define GUARD_List_h
#include "Element.h"
#include "List_iter.h"
template <typename T>
class List {
public:
List() : begins(new Element<T>), ends(new Element<T>), Element_count(0) {
begins->t_flag = 'b';
ends->t_flag = 'e';
// double link: begins & ends
begins->next = ends;
ends->prev = begins;
}
virtual ~List() {
while (begins->next != ends) {
begins->prev = begins->next;
begins->next = begins->next->next;
delete begins->prev;
}
delete begins;
delete ends;
}
typedef List_iter<T> iterator;
iterator begin(void) const {
iterator it(begins);
return it;
}
iterator end(void) const {
iterator it(ends);
return it;
}
void push_back(const T val) {
Element<T>* elem = new Element<T>; // create: new-elem
elem->data = val; // set data
elem->prev = ends->prev; // link: new-elem to last-data-elem
ends->prev->next = elem; // link: last-data-elem to new-Element
elem->next = ends; // link: new-elem to List-end
ends->prev = elem; // link: List-end to new-elem
Element_count++; // update: when List grows
}
T at(const size_t pos) const {
return get_Element(pos)->data;
}
void del(const size_t pos) const {
Element<T>* elem = get_Element(pos); // get: Element for deletion
elem->prev->next = elem->next; // rejoin: double link
elem->next->prev = elem->prev; // rejoin: double link
delete elem;
Element_count--; // update: when List shrinks
}
void clear(void) {
Element<T>* ep = begins->next;
Element<T>* ep_next = ep->next;
while (ep->t_flag != 'e'){
delete ep;
ep = ep_next;
ep_next = ep->next;
}
begins->next = ends;
ends->prev = begins;
//begins->data = 0r;
//ends->elem_ID = 0;
Element_count = 0;
}
size_t size(void) const {
return Element_count;
}
bool empty(void) const {
if (Element_count == 0){ return true; }
else { return false; }
}
private:
Element<T>* begins; // List begins
Element<T>* ends; // List ends
size_t Element_count; // List size
Element<T>* get_Element(const size_t pos) const {
if (empty()) {
std::cerr << "No Element - Empty List";
throw;
}
if (pos < 0 || pos >= Element_count){
std::cerr << "No Element - Out of Range";
throw;
}
iterator it;
// Determine the more efficent iteration direction(forward or reverse) ?
if ((Element_count / 2) > pos) {
it = begin();
for (size_t i = 0; i <= pos; i++){
it++;
}
}
else {
it = end();
for (size_t i = size() - pos; i > 0; i--){
it--;
}
}
return it.elem;
}
};
#endif
Element:
#ifndef GUARD_Element_h
#define GUARD_Element_h
template <class T>
class List;
template <class T>
class List_iter;
template <class T>
class Element {
public:
Element() : prev(nullptr), next(nullptr), data(), t_flag(' ') {}
virtual ~Element() {
delete prev;
delete next;
}
friend List<T>;
friend List_iter<T>;
private:
Element<T> *prev;
Element<T> *next;
T data;
int elem_ID;
char t_flag;
};
#endif
List_iter:
#ifndef GUARD_List_iter_h
#define GUARD_List_iter_h
template <class T>
class List;
template <class T>
class List_iter {
public:
List_iter(Element<T>* e = nullptr) : elem(e) {}
virtual ~List_iter() {
delete elem;
}
friend List<T>;
T operator*(void){
if (elem->t_flag == 'e'){
elem = elem->prev;
}
else if (elem->t_flag == 'b'){
elem = elem->next;
}
return elem->data;
}
Element<T>* operator++(void) {
if (elem->next->t_flag == 'e'){
return nullptr;
}
elem = elem->next;
return elem;
}
Element<T>* operator--(void) {
if (elem->prev->t_flag == 'b'){
return nullptr;
}
elem = elem->prev;
return elem;
}
List_iter operator+(const int val) {
for (int i = 0; i < val; i++){
this->elem = this->elem->next;
}
return *this;
}
List_iter operator-(const int val) {
for (int i = 0; i < val; i++){
this->elem = this->elem->prev;
}
return *this;
}
bool operator!=(const List_iter& rhs) const {
return rhs.elem != elem;
}
bool operator>(const List_iter& rhs) const {
return (this->elem->elem_ID > rhs.elem->elem_ID);
}
bool operator<(const List_iter& rhs) const {
return (this->elem->elem_ID < rhs.elem->elem_ID);
}
bool operator>=(const List_iter& rhs) const {
return (this->elem->elem_ID >= rhs.elem->elem_ID);
}
bool operator<=(const List_iter& rhs) const {
return (this->elem->elem_ID <= rhs.elem->elem_ID);
}
private:
Element<T>* elem;
};
#endif
main:
#include <iostream>
#include "List.h"
int main() {
List<int> ls;
List<int>::iterator begin = ls.begin();
List<int>::iterator end = ls.end();
List<int>::iterator iter = begin;
std::cout << "Attempt to retrieve data from empty list: ls.at(3)" << std::endl;
std::cout << "--------------------------------------------------" << std::endl;
//std::cout << ls.at(3) << std::endl << std::endl;
std::cout << "Test: growing list does not invalidate iter" << std::endl;
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Empty list" << std::endl << std::endl;
std::cout << "begin addr: " << &begin << " " << std::endl;
std::cout << "end addr: " << &end << " " << std::endl;
std::cout << std::endl << "Add data to list: 33 " << std::endl << std::endl;
ls.push_back(33);
std::cout << "begin addr: " << &begin << " " << std::endl;
std::cout << "end addr: " << &end << " " << std::endl;
std::cout << std::endl << "Add data to list: 856 " << std::endl << std::endl;
ls.push_back(856);
std::cout << "begin addr: " << &begin << " " << std::endl;
std::cout << "end addr: " << &end << " " << std::endl;
std::cout << "clear() " << std::endl << std::endl;
ls.clear();
std::cout << std::endl << std::endl;
std::cout << "Add data to list: 0 1 2 3 4 5 6 7 8 9" << std::endl;
std::cout << "-------------------------------------------------" << std::endl;
for (int i = 0; i != 10; i++){
ls.push_back(i);
}
std::cout << std::endl << std::endl;
std::cout << "data# begin+4" << std::endl;
std::cout << "-------------" << std::endl;
std::cout << *(iter + 4) << std::endl;
std::cout << std::endl << std::endl;
std::cout << "data# begin->end" << std::endl;
std::cout << "----------------" << std::endl;
iter = begin;
while (iter++){
std::cout << *iter << " ";
}
std::cout << std::endl << std::endl << std::endl;
std::cout << "data# end->begin" << std::endl;
std::cout << "----------------" << std::endl;
iter = end;
while (iter--){
std::cout << *iter << " ";
}
std::cout << std::endl << std::endl << std::endl;
std::cout << "for/iter: begin->end" << std::endl;
std::cout << "----------------" << std::endl;
for (iter = begin; iter++;){
std::cout << *iter << " ";
}
std::cout << std::endl << std::endl << std::endl;
std::cout << "iter arith: +4 +1 -1" << std::endl;
std::cout << "--------------------" << std::endl;
iter = ls.begin();
iter = iter + 4;
std::cout << *iter << " ";
std::cout << *(iter + 1) << " ";
std::cout << *(iter - 1) << " ";
std::cout << std::endl << std::endl << std::endl;
std::cout << "data#: (0)(1)(2)(3)(4)(5)(6)(7)(8)(9)" << std::endl;
std::cout << "-------------------------------------" << std::endl;
for (int i = 0; i != 10; i++){
std::cout << ls.at(i) << " ";
}
//ls.clear();
List<std::string> ls_str;
ls_str.push_back("Hello");
ls_str.push_back("World");
return 0; // breakpoint
}

new Element called, therefore owned by List, so only List can delete Element. List_iter doesn't require a destructor because it only contains a pointer.

Related

Check if queue is sorted in ascending order hanging

I can't seem to figure out why the program below is not running as intended.
After entering a negative integer value and breaking the first while loop in main, program control does not proceed.
I tried flushing the output stream at various key points but the issue persists.
#include <iostream>
#include <queue>
bool checkValidity(const std::queue<int>& q) {
for(auto i = q.front(); i != q.back(); ++i){
if (q.empty() || q.size() <= 1){
std::cout << "invalid entry, insufficient elements" << '\n';
return false;
break;
}
if (i > ++i) {
std::cout << "invalid entry, not properly sorted" << '\n';
return false;
break;
}
}
std::cout << "valid entry, properly sorted" << '\n';
return true;
}
const char* bool_cast(const bool b) {
return b ? "true" : "false";
}
int main () {
std::queue<int> numbers;
int temp;
std::cout << "Pushing..." << '\n';
while(temp >= 0){
std::cout << "Enter numbers: ";
std::cin >> temp;
if(temp >= 0){
numbers.push(temp);
}
}
bool ck = checkValidity(numbers);
std::cout << bool_cast(ck) << '\n';
std::cout << "{ ";
while(numbers.size() > 0){
std::cout << numbers.front();
numbers.pop();
std::cout << " ";
}
std::cout << "}" << '\n';
return 0;
}
You cannot iterate through the queue, therefore to iterate you need to copy the queue to another queue and then traverse by poping the elements from the queue. and comparing the elements.
Inline comments added for better understanding of the code.
bool checkValidity(const std::queue<int>& q) {
if (q.empty() || q.size() <= 1){ // This can be outside the loop and checked only onces
std::cout << "invalid entry, insufficient elements" << '\n';
return false;
}
std::queue<int> numbers=q; // a new queue to copy the queue
int first=numbers.front(); // to compare we need to variable first and second
numbers.pop();// pop the first value,as it is stored in first variable
int second;
while(!numbers.empty()){
second=numbers.front();
numbers.pop();
if (first> second) { // compare the first and second variable
std::cout << "invalid entry, not properly sorted" << '\n';
return false;
break;
}
first=second; // assign second to first and traverse the reamining queue
}
std::cout << "valid entry, properly sorted" << '\n';
return true;
}
Hope this help.
Inherited from std::queue and use its protected member Container c; to access begin() and end() of the underlying container as previously done here std::queue iteration.
#include <iostream>
#include <queue>
#include <deque>
#include <iterator>
template<typename T, typename Container=std::deque<T> >
class iterable_queue : public std::queue<T,Container>
{
public:
typedef typename Container::iterator iterator;
typedef typename Container::const_iterator const_iterator;
iterator begin() { return this->c.begin(); }
iterator end() { return this->c.end(); }
const_iterator begin() const { return this->c.begin(); }
const_iterator end() const { return this->c.end(); }
};
bool checkValidity(iterable_queue<int>& q) {
if (q.empty() || q.size() <= 1){
std::cout << "invalid entry, insufficient elements" << '\n';
return false;
}
while(q.size()){
auto i = q.begin();
auto j = ++q.begin();
for(; i < q.end() && j < ++q.end();){
std::cout << *i << " " << *j << '\n';
if (*(i) > *(j)) {
std::cout << "invalid entry, not properly sorted" << '\n';
return false;
}
i++, j++;
}
std::cout << "valid entry, properly sorted" << '\n';
return true;
}
std::cout << "invalid entry, insufficient elements" << '\n';
return false;
}
const char* bool_cast(const bool b) {
return b ? "true" : "false";
}
int main () {
iterable_queue<int> numbers;
int temp;
std::cout << "Pushing..." << '\n';
while(temp >= 0){
std::cout << "Enter numbers: ";
std::cin >> temp;
if(temp >= 0){
numbers.push(temp);
}
}
bool ck = checkValidity(numbers);
std::cout << bool_cast(ck) << '\n';
std::cout << "{ ";
while(numbers.size() > 0){
std::cout << numbers.front();
numbers.pop();
std::cout << " ";
}
std::cout << "}" << '\n';
return 0;
}

Why is the destructor of this custom allocator being called twice in GCC/MSVS's stdlib

I've been trying to write a simple allocator, I've written a minimal one that just logs its calls.
When trying to use it in some simple std::vector operations - at least on GCC and Visual Studio - the logged behaviour looks intuitive except that the destructor appears to be called before all of the allocations are requested, as well as at the end. On clang everything works as one would expect, so I'm not sure if this is just a compiler issue.
Assuming it's not a compiler error, what's missing from this allocator; or is my understanding of how the allocator is being called wrong and it's just fine?
I have the code below as a live demo here
#include <ios>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
using std::size_t;
struct Indexer
{
static size_t nextId, objectsAlive;
};
size_t Indexer::nextId, Indexer::objectsAlive;
template<typename T>
class DebugAllocator : protected Indexer
{
static std::string formatPointer(const void* p)
{
std::ostringstream s;
s << "[93m0x" << std::hex << std::uppercase << uintptr_t(p) << "[0m";
return s.str();
}
static std::string formatFunctionName(const char* functionName)
{
return "[96m" + std::string(functionName) + "[0m";
}
static std::string indentation()
{
return std::string((objectsAlive + 1) * 4, ' ');
}
public:
using value_type = T;
using pointer = value_type*;
using size_type = std::make_unsigned_t<typename std::pointer_traits<pointer>::difference_type>;
size_t id;
DebugAllocator() noexcept
: id(nextId++)
{
std::cerr << indentation() << "DebugAllocator::" << formatFunctionName(__func__) << '(' << id << ")\n";
++objectsAlive;
}
template<typename T_rhs>
DebugAllocator(const DebugAllocator<T_rhs>& rhs) noexcept
: id(nextId++)
{
std::cerr << indentation() << "DebugAllocator::" << formatFunctionName(__func__) << '(' << id << ", " << rhs.id << ")\n";
++objectsAlive;
}
template<typename T_rhs>
DebugAllocator& operator=(const DebugAllocator<T_rhs>& rhs) noexcept
{
std::cerr << indentation() << id << " = DebugAllocator::" << formatFunctionName(__func__) << '(' << id << ", " << rhs.id << ")\n";
}
~DebugAllocator() noexcept
{
--objectsAlive;
std::cerr << indentation() << "DebugAllocator::" << formatFunctionName(__func__) << '(' << id << ")\n";
}
pointer allocate(size_type n) const
{
value_type* const p((value_type*) new char[sizeof(value_type) * n]);
std::cerr << indentation() << formatPointer(p) << " = DebugAllocator::" << formatFunctionName(__func__) << '(' << id << ", " << n << ")\n";
return p;
}
void deallocate(pointer p, size_type n) const noexcept
{
std::cerr << indentation() << "DebugAllocator::" << formatFunctionName(__func__) << '(' << id << ", " << formatPointer(p) << ", " << n << ")\n";
delete[] (value_type*) p;
}
bool operator==(const DebugAllocator& rhs) const noexcept
{
std::cerr << indentation() << std::boolalpha << true << " = DebugAllocator::" << formatFunctionName(__func__) << '(' << id << ", " << rhs.id << ")\n";
return true;
}
bool operator!=(const DebugAllocator& rhs) const noexcept
{
std::cerr << indentation() << std::boolalpha << false << " = DebugAllocator::" << formatFunctionName(__func__) << '(' << id << ", " << rhs.id << ")\n";
return false;
}
};
int main()
{
std::vector<int, DebugAllocator<int>> v{3};
v.push_back(1);
v.push_back(2);
v.emplace_back(1);
v.insert(std::begin(v) + 2, 4);
v.erase(std::begin(v) + 3);
std::string separator;
for (int& x : v)
{
std::cerr << separator << std::move(x);
separator = ", ";
}
std::cerr << '\n';
}
GCC / MSVS log:
DebugAllocator::DebugAllocator(0)
0xF86C50 = DebugAllocator::allocate(0, 1)
DebugAllocator::~DebugAllocator(0)
0xF86CA0 = DebugAllocator::allocate(0, 2)
DebugAllocator::deallocate(0, 0xF86C50, 1)
0xF86C50 = DebugAllocator::allocate(0, 4)
DebugAllocator::deallocate(0, 0xF86CA0, 2)
0xF86C20 = DebugAllocator::allocate(0, 8)
DebugAllocator::deallocate(0, 0xF86C50, 4)
3, 1, 4, 1
DebugAllocator::deallocate(0, 0xF86C20, 8)
DebugAllocator::~DebugAllocator(0)
clang log:
DebugAllocator::DebugAllocator(0)
0xD886F0 = DebugAllocator::allocate(0, 1)
0xD88710 = DebugAllocator::allocate(0, 2)
DebugAllocator::deallocate(0, 0xD886F0, 1)
0xD886F0 = DebugAllocator::allocate(0, 4)
DebugAllocator::deallocate(0, 0xD88710, 2)
0xD88730 = DebugAllocator::allocate(0, 8)
DebugAllocator::deallocate(0, 0xD886F0, 4)
3, 1, 4, 1
DebugAllocator::deallocate(0, 0xD88730, 8)
DebugAllocator::~DebugAllocator(0)
Apparently
template<typename T_rhs>
DebugAllocator(const DebugAllocator<T_rhs>& rhs)
does not count as a copy constructor. So a compiler-generated copy-constructor is called that you didn't observe.

Operator Overloading solution

i have made a c++ code. An MList that holds items in it. I overloaded the << operator to print the values in MList in a particular format. Here is the code:
friend ostream& operator<<(ostream &out, const MSet<V> &m)
{
string s = "";
s += "Size " + to_string(m.size_) + "\n";//out << m.size() << endl;
s += "Cap " + to_string(m.capacity_) + "\n"; //out << m.capacity() << endl;
for (int i = 0; i < m.size_; i++)
{
if (i < m.size_ - 1)
s += m.ary[i].element + ",";//out << m.ary[i].element << ",";
else
s += m.ary[i].element;
}
//cout << "String : " << s;
return out << s;
}
But it does not print correct value. It prints the size and capacity right but not the values. Instead of values, it prints some signs like heart:
You can see it prints size and capacity right but not the values. Here is the relevant code. I am executing case 2 only right now:
#include<iostream>
using std::cout; using std::endl;
using std::ostream; using std::cin; using std::boolalpha;
#include<string>
using std::string;
using namespace std;
template <class V>
struct SetElement
{
V element;
int cnt;
SetElement() = default;
SetElement(V v) : element(v){}
};
template <class V>
ostream &operator<<(ostream & o,const SetElement<V> &p)
{
return o << p.element;
}
template <class V>
class MSet
{
private:
SetElement<V> *ary;
size_t capacity_;
size_t size_;
public:
MSet(V val)
{
capacity_ = 2;
ary = new SetElement<V>[capacity_];
ary[0].element = val;
ary[0].cnt = 1;
size_ = 1;
}
SetElement<V>* find(V val)
{
SetElement<V> *found = nullptr;
bool yes = false;
for (int i = 0; i < size_ && !yes; i++)
{
if (ary[i].element == val)
{
found = &ary[i];
yes = true;
}
}
return found;
}
friend ostream& operator<<(ostream &out, const MSet<V> &m)
{
string s = "";
s += "Size " + to_string(m.size_) + "\n";//out << m.size() << endl;
s += "Cap " + to_string(m.capacity_) + "\n"; //out << m.capacity() << endl;
for (int i = 0; i < m.size_; i++)
{
if (i < m.size_ - 1)
s += m.ary[i].element + ",";//out << m.ary[i].element << ",";
else
s += m.ary[i].element;
}
//cout << "String : " << s;
return out << s;
}
};
int main(){
int test;
long l1, l2, l3;
cin >> test;
cout << boolalpha;
switch (test){
// ...
case 2: {
cin >> l1 >> l2;
MSet<long> m_l(l1);
auto p = m_l.find(l1);
if (p != nullptr)
cout << *p << endl;
else
cout << "Val:" << l1 << " not found " << endl;
p = m_l.find(l2);
if (p != nullptr)
cout << *p << endl;
else
cout << "Val:" << l2 << " not found " << endl;
//cout << "MList \n";
cout << m_l;
break;
}
// ...
}
}
You're adding the values into a temporary string, which may involve implicit conversions depending of the template type (here your numerical values were converted into characters).
Just print the values, without the temporary string:
friend ostream& operator<<(ostream &out, const MSet<V> &m)
{
out << "Size " << m.size_ << endl;
out << "Cap " << m.capacity_ << endl;
for (int i = 0; i < m.size_; i++)
{
if (i < m.size_ - 1)
out << m.ary[i].element << ",";
else
out << m.ary[i].element;
}
return out;
}

When calling delete for LinkedList, variable is being assigned different memory

I am using a linked list to store information on binary bits. Degree tells which power to raise an integer, 2, to.
The problem occurs in my set_bit method. It is supposed to delete the node pointer "currentSet" once the "target" node pointer is found. However instead of setting "currentSet" to null/releasing the memory, currentSet is being given a different, lower memory address. Why is this? What am I doing wrong? The program works when I explicitly sell currentSet to nullptr but shouldn't delete currentSet do this as well?
Here is the implementation of header
//file is "binary.cpp"
#include <iostream>
#include "binary.h"
//using std::cout;
Binary::Binary(int x) {
firstTerm = nullptr;
while (x > 0) {
unsigned int degree = (unsigned int) (log(float(x)) / log(float(2)));
set_bit(1, degree);
x -= (int) pow(float(2), float(degree));
}
}
Binary::~Binary() {
BinaryNode *temp;
while (firstTerm != nullptr) {
temp = firstTerm->next;
delete firstTerm;
firstTerm = temp;
}
}
void Binary::set_bit(int bit, int degree) {
BinaryNode *currentSet = firstTerm;
BinaryNode *target;
std::cout << "get_bit returns " << get_bit(degree) << std::endl;
if (bit == 0 && get_bit(degree)) {
std::cout << "bit = 0 " << std::endl;
std::cout << "currentSet->degree " << currentSet->degree << std::endl;
if (currentSet->degree == degree) {
std::cout << "in if" << std::endl;
firstTerm = currentSet->next;
delete currentSet;
std::cout << "end if" << std::endl;
}
else {
target = currentSet;
std::cout << "in else" << std::endl;
while (currentSet != nullptr) {
if (currentSet->degree == degree) {
std::cout << "in nested if" << std::endl;
//std::cout << "currentSet->degree = " << currentSet->degree << std::endl;
target->next = currentSet->next;
std::cout << "currentSet before delete " << currentSet << std::endl;
delete currentSet;
std::cout << "currentSet " << currentSet << "\nend nested if" << std::endl;
}
else {
std::cout << "in nested else" << std::endl;
std::cout << "firstTerm->next = " << firstTerm->next << std::endl;
std::cout << "currentSet->next = " << currentSet->next << std::endl;
target = currentSet;
currentSet = currentSet->next;
std::cout << "currentSet->next = " << currentSet->next << std::endl;
std::cout << "end nested else\n";
}
}
}
}
else if (bit == 1 && get_bit(degree) == 0) {
std::cout << "bit = 1" << std::endl;
firstTerm = new BinaryNode(degree, firstTerm);
/*if (firstTerm->next nullptr) {
currentSet = firstTerm;
}*/
std::cout << "firstTerm = " << firstTerm << std::endl;
std::cout << "firstTerm->degree = " << firstTerm->degree << std::endl;
std::cout << "firstTerm->next = " << firstTerm->next << std::endl;
}
}
int Binary::get_bit(int degree) const {
BinaryNode *currentGet = firstTerm;
while (currentGet != nullptr) {
//std::cout << "currentGet != nullptr";
if (currentGet->degree == degree) {
return 1;
}
currentGet = currentGet->next;
}
return 0;
}
Here is the header
//file is "binary.h"
#ifndef _BINARY_H_
#define _BINARY_H_
#include <iostream>
class Binary {
private:
struct BinaryNode {
int degree;
BinaryNode* next;
BinaryNode(int d, BinaryNode* n): degree(d),next(n) {}
};
BinaryNode *firstTerm;
public:
// default constructor
Binary() {
firstTerm = nullptr;
}
void set_bit(int b, int d);
int get_bit(int d) const;
#endif
Here is the tester file
//file is "binary_main.cpp
#include <iostream>
#include "binary.h"
using namespace std;
int main (void)
{
cout << "\nTESTING GET AND SET METHODS" << endl;
b1.set_bit(1, 2);
b1.set_bit(1, 5);
b1.set_bit(1, 0);
b1.set_bit(0, 2);
}
edited
Explicitly set currentSet to nullptr,
answer was found using information from n.m.

Errors within Main program using classes

I just have a few errors of the same type in my main program. My college professor is not answering my emails so I have to resort to asking you guys. In my main program I have several errors somewhat similar to this: "request for member which is of non-class type." Program01 is basically testing every function in ListType.h, OListType.h, and UListType.h to make sure everything works correctly. Any help you can provide in a timely fashion will be appreciated.
Here is ListType.h:
#ifndef LISTTYPE_H_INCLUDED
#define LISTTYPE_H_INCLUDED
#include <iostream>
class ListType {
public:
ListType(size_t=10);
ListType(const ListType&);
virtual ~ListType();
virtual bool insert(int)=0;
virtual bool eraseAll();
virtual bool erase(int)=0;
virtual bool find(int) const=0;
size_t size() const;
bool empty() const;
bool full() const;
friend std::ostream& operator << (std::ostream&, const ListType&);
const ListType& operator= (const ListType&);
protected:
int *items;
size_t capacity;
size_t count;
};
#endif // LISTTYPE_H_INCLUDED
Here is ListType.cpp:
#include "ListType.h"
ListType::ListType (size_t a) {
capacity = a;
count = 0;
items = new int [capacity];
}
ListType::ListType(const ListType& newlist) {
capacity = newlist.capacity;
count = newlist.count;
items = new int [capacity];
for (size_t i = 0; i < count; ++i)
items[i] = newlist.items[i];
}
ListType::~ListType() {
delete [] items;
}
bool ListType::eraseAll() {
count = 0;
return 0;
}
size_t ListType::size() const {
return (count);
}
bool ListType::empty() const {
return (count == 0);
}
bool ListType::full() const {
return (count == capacity);
}
std::ostream& operator << (std::ostream& out, const ListType& my_list) {
if (!my_list.empty()) {
for (size_t i = 0; i < my_list.count; ++i){
out << my_list.items[i] << ',';
}
}
return out;
}
const ListType& ListType::operator= (const ListType& rightObject) {
if (this != & rightObject) {
delete [] items;
capacity = rightObject.capacity;
count = rightObject.count;
items = new int[capacity];
for (size_t i = 0; i < count; ++i) {
items[i] = rightObject.items[i];
}
}
return *this;
}
Here is UListType.h:
#ifndef ULISTTYPE_H_INCLUDED
#define ULISTTYPE_H_INCLUDED
#include <iostream>
class UListType: public ListType {
public:
UListType(size_t=10);
bool insert(int);
bool erase(int);
bool find(int) const;
};
#endif // ULISTTYPE_H_INCLUDED
Here is UListType.cpp:
#include "ListType.h"
#include "UListType.h"
UListType::UListType (size_t c): ListType(c) {}
bool UListType::insert(int item) {
if (full()) {
int *newitems;
capacity *=2;
newitems = new int[capacity];
for (size_t i =0; i < count; ++i){
newitems[i] = items[i];
}
delete [] items;
items = newitems;
}
items[count++] = item;
return true;
}
bool UListType::erase(int item) {
bool result = false;
size_t i=0;
while ( i < count && items [i] != item) {
++i;
}
if (i < count) {
items[i] = items[-- count];
result = true;
}
return result;
}
bool UListType::find(int item) const {
size_t i = 0;
while (i < count && items [i] != item) {
++i;
}
return i < count;
}
Here is OListType.h:
#ifndef OLISTTYPE_H_INCLUDED
#define OLISTTYPE_H_INCLUDED
#include <iostream>
class OListType: public ListType {
public:
OListType(size_t=10);
bool insert(int);
bool erase(int);
bool find(int) const;
};
#endif // OLISTTYPE_H_INCLUDED
Here is OListType.cpp:
#include "ListType.h"
#include "OListType.h"
OListType::OListType(size_t c): ListType(c) {}
bool OListType::insert(int item) {
size_t i = count;
if (full()) {
int *newitems;
capacity *=2;
newitems = new int[capacity];
for(size_t j=0; j < count; ++j) {
newitems[j] = items[i];
}
delete [] items;
items = newitems;
}
while (i > 0 && items[i-1] > item){
items[count++] = item;
}
return true;
}
bool OListType::erase(int item) {
bool found=false;
size_t i=0, j= count-1, mid;
while (i <= j && !(found)){
mid = (i + j)/2;
if (item < items [mid])
j = mid - 1;
else if (item > items [mid])
i = mid + 1;
found = items [mid] == item;
}
if (found) {
for (i = mid; i < count - 1; ++i) {
items [i] = items [i +1];
}
--count;
}
return found;
}
bool OListType::find (int item) const {
bool found=false;
size_t i=0, j= count-1, mid;
while (i <= j && !(found)){
mid = (i + j)/2;
if (item < items [mid])
j = mid - 1;
else if (item > items [mid])
i = mid + 1;
found = items [mid] == item;
}
return found;
}
Here is Program01.cpp:
#include "ListType.h"
#include "UListType.h"
#include "OListType.h"
#include <iostream>
using namespace std;
int main() {
OListType list[5] = {165, 16, 118, 212, 104};
UListType ranlist[10] = {243, 300, 154, 153, 592, 124, 195, 217, 289, 405};
UListType UListAssignmentTest;
OListType OListAssignmentTest;
cout << "The Ordered List before operations:" << endl;
cout << list << endl << endl;
if(list.empty()) **<-- HERE BE THE ERROR**
cout << "The list is empty, therefore it is true.";
else
cout << "The list is full or partially full, therefore it is false";
cout << endl << endl;
if(list.full())
cout << "The list is full, therefore it is true.";
else
cout << "The list is partially full or empty, therefore it is false";
cout << endl << endl;
list.insert(25);
cout << endl << endl;
cout << "The Ordered list after Insert:" << endl;
cout << list << endl << endl;
list.find(25);
cout << endl << endl;
list.find(30);
cout << endl << endl;
list.erase(25);
cout << endl << endl;
cout << "The Ordered List after Erase:" << endl;
cout << list << endl << endl;
cout << "The Unordered List before operations:" << endl;
cout << ranlist << endl << endl;
if(ranlist.empty())
cout << "The list is empty, therefore it is true.";
else
cout << "The list is full or partially full, therefore it is false";
cout << endl << endl;
if(ranlist.full())
cout << "The list is full, therefore it is true.";
else
cout << "The list is partially full or empty, therefore it is false";
cout << endl << endl;
ranlist.insert(25);
cout << endl << endl;
cout << "The Unordered List after Insert:" << endl;
cout << ranlist << endl << endl;
ranlist.find(25);
cout << endl << endl;
ranlist.find(30);
cout << endl << endl;
ranlist.erase(25);
cout << endl << endl;
cout << "The Unordered List after Erase:" << endl;
cout << ranlist << endl << endl;
cout << "Testing Ordered List Assignment Operator" << endl;
OListAssignmentTest = list;
cout << OListAssignmentTest << endl << endl;
cout << "Testing Unordered List Assignment Operator" << endl;
UListAssignmentTest = ranlist;
cout << UListAssignmentTest << endl << endl
cout << "Testing Ordered List Copy Constructor" << endl;
OListType OListVariable = list;
cout << OListVariable << endl << endl;
cout << "Testing Unordered List Copy Constructor" << endl;
UListType UListVariable = ranlist;
cout << UListVariable << endl << endl;
cout << "Testing Erase All for OList" << endl;
list.eraseAll();
cout << "OList values now: " << list.empty() << endl << endl;
cout << "Testing Erase All for UList" << endl;
ranlist.eraseAll();
cout << endl << "UList values now: " << ranlist.empty() << endl;
return 0;
}
OListType list[5] = {165, 16, 118, 212, 104};
This line declares an array of 5 OListType types. This doesn't seem correct.
You want to declare one OLIstType and insert 5 values into it. If not, please clarify what that line is supposed to denote.
Here is probably what you are supposed to do:
OListType list;
list.insert(165);
list.insert(16); // etc...