How is memory allocated to instances of class with array member? - c++

In my understanding, under usual conditions, array is being allocated memory at compile time, but what happens when array is a member variable, and there is pretty much nothing to allocate memory to during compilation. Does it get implicitly dynamically-allocated, when instance of that class is created?
class Arr{
public:
int arr[10];
};
Arr doSomething(Arr &arg){
return arg; //copy of arg created; 'copy=new int[10]' at this point?
}
int main(){
Arr temp;
doSomething(temp);
//if returned object's array was dynamically initialized
//will it result the array in temp being released twice?
}
UPD. In my case, situation rises when I try to subract A-B where B>A. In these cases I can access array to read from it, but modifying its values leads to garbage. Moreover, final output in main is fine. Here's full code:
#include <iostream>
using namespace std;
const int MAX_ARRAY_SIZE=256;
char* getOperatorIndex(char* equationString);
bool isOperator(char characterDec);
int* toIntArray(char* firstInA, char* lastInA, int* firstInB);
class Number{
int* firstInNumber;
int* lastInNumber;
int number[MAX_ARRAY_SIZE];
public:
Number();
~Number();
bool operator<(Number& b);
int& operator[](int index);
Number operator-(Number& b);
void print();
int length(){return lastInNumber-firstInNumber;}
int*& lastPtr(){return lastInNumber;}
int*& firstPtr(){return firstInNumber;}
};
Number::Number(){
firstInNumber=number;
lastInNumber=number;
}
Number::~Number(){
cout<<"number destroyed"<<endl;
}
int& Number::operator[](int index){
return number[index];
}
bool Number::operator<(Number& b){
if(length()>b.length())return false;
if(length()<b.length())return true;
for(int a=0;a<length();++a){
if(number[a]>b[a])return false;
if(number[a]<b[a])return true;
}
return false;
}
void Number::print(){
for(int a=0; a<=length(); ++a){
cout<<number[a];
}
cout<<endl;
}
Number Number::operator-(Number& b){
Number result;
if(*this < b)
{
result=b-*this;
cout<<*result.lastPtr()<<endl;
result.print();
*result.lastPtr()*=-1; // GARBAGE HERE
cout<<*result.lastPtr()<<endl;
return result;
}
result[0]=0;
for(int q=0; q<=length(); ++q)
{
if(b.length()-q >= 0)
{
result[q]+=(*this)[length()-q]-b[b.length()-q];
if(result[q] < 0)
{
result[q]+=10;
result[q+1]=-1;
}
else
{
result[q+1]=0;
}
}
else
{
result[q]+=(*this)[length()-q];
}
++result.lastPtr();
}
do{
--result.lastPtr();
}while(!*result.lastPtr());
return result;
}
int main(){
char equationArray[MAX_ARRAY_SIZE*2+1]; // operandA(<=256) operator(1) operandB(<=256)
Number a,b;
cin>>equationArray;
char* operatorPtr=getOperatorIndex(equationArray);
a.lastPtr()=toIntArray(equationArray, operatorPtr, a.firstPtr());
b.lastPtr()=toIntArray(operatorPtr+1, operatorPtr+strlen(operatorPtr), b.firstPtr());
a.print();
b.print();
Number c;
switch(*operatorPtr){
case '-':
c=a-b;
break;
}
c.print();
}
char* getOperatorIndex(char* equationString){
while(!isOperator(*++equationString));
return equationString;
}
bool isOperator(char characterDec){
if(characterDec>='*' & characterDec<='/')return true;
return false;
}
int* toIntArray(char* firstInA, char* lastInA, int* firstInB){
while(lastInA-firstInA>0){
*firstInB=*firstInA-'0';
++firstInB;
++firstInA;
}
return --firstInB;
}

All data members of a class have the same storage-duration as the class' object created. Hence in:
int main(){
Arr temp;
doSomething(temp);
}
The data member temp.arr which is of type int[10]; also has automatic storage-duration.. (or what is inappropriately known as "stack object")
Arr doSomething(Arr &arg){
return arg; //copy of arg created; 'copy=new int[10]' at this point?
}
No, there is no heap allocation here. rather a member-wise copy by the implicit copy constructor. See How are C++ array members handled in copy control functions?

Related

c++ Copy constructors and destructors

I am learning constructors and Destructors in c++; Help me grasp my mistakes even if they are silly...
HERE is a code I have written to perform addition using classes in c++; This creates two summands of datatype num and employs the constructor sum() to perform sum of the two numbers; However when everything was goin' alright, I stumbled upon creating a copy constructor for num , (Although not necessary but still for practice)... without the dynamic object of the class sum it is not possible to run the code anyway(without removing the copy constructor)... Help me improve my code and my mistakes in the code below; Also I wanna know how to make use of the copy constructor in this program; the problem being that in the destructor the delete operation is being performed multiple times on the same piece of memory (I suppose)
Here's my Code
#include<iostream>
#include<new>
using namespace std;
class num
{
public:
int *a;
num(int x)
{
try
{
a=new int;
}
catch(bad_alloc xa)
{
cout<<"1";
exit(1);
}
*a=x;
}
num(){ }
num(const num &ob)
{
try
{
a=new int;
}
catch(bad_alloc xa)
{
cout<<"1''";
exit(2);
}
*a=*(ob.a);
}
~num()
{
cout<<"Destruct!!!";
delete a;
}
};
class sum:public num
{
public:
int add;
sum(num n1,num n2)
{
add=*(n1.a)+*(n2.a);
}
int getsum()
{
return add;
}
};
int main()
{
num x=58;
num y=82;
sum *s=new sum(x,y);
cout<<s->getsum();
delete s;
return 0;
}
I may miss something - didn't use new/delete for too long, but tried to correct all what I noticed.
P.S. always use smart pointers.
#include <iostream>
#include <exception>
#include <new>
using namespace std;
int* allocate(const char* err_msg, int exit_code)
{
int* a = nullptr;
try
{
a = new int;
}
catch (bad_alloc&)
{
cout << err_msg << endl;
exit(exit_code);
}
return a;
}
class num
{
int* a = nullptr; // always should be initialized here
public:
num() noexcept : a(nullptr) // or here
{}
/*explicit*/ num(int x) : a(allocate("1", 1))
{
*a = x;
}
num(const num& ob) : a(allocate("1''", 2))
{
*a = *(ob.a);
}
// rule of zero/three/five
// default copy assignment will copy pointer and one int will be leaked and one will be deleted twice
num& operator =(const num& ob)
{
if (&ob == this)
{
return *this;
}
*a = *(ob.a);
return *this;
}
~num()
{
cout << "Destruct!!!";
delete a;
a = nullptr; // usefull for debug
}
int value() const
{
if (a == nullptr)
{
throw runtime_error("a == nullptr");
}
return *a;
}
};
class sum
{
int add = 0;
public:
sum(const num& n1, const num& n2)
{
add = n1.value() + n2.value();
}
int getsum() const
{
return add;
}
};
int main()
{
const num x = 58;
const num y = 82;
const sum* s = new sum(x, y);
cout << s->getsum() << endl;
delete s;
return 0;
}

glibc detected error, possible memory leak?

Header File (IntegerSet.h)
#include<iostream>
#include<string>
using namespace std;
class IntegerSet{
public:
unsigned int set[15];
unsigned int empty_set[15];
IntegerSet();
IntegerSet(int[],int);
IntegerSet unionOfsets(IntegerSet);
IntegerSet intersectionOfSets(IntegerSet);
void insertElement(int);
void deleteElement(int);
void printSet();
bool isEqualTo(IntegerSet);
void emptySet();//Set all elements of set to 0
void inputSet();//Reads values from the user into set
bool validEntry(int);//Determines a valid entry to the set
};
Implementation File (IntegerSet.cpp)
//Class implementation file
#include "IntegerSet.h"
using namespace std;
IntegerSet::IntegerSet(){
for(int i=0;i<100;i++){
empty_set[i]=0;
}
}
IntegerSet::IntegerSet(int arr[],int size){
int min;//Use to hold the value for the sorting algorithm
int counter;//Used to count how many values need to be removed from the new array
for(int i=0;i<size-1;i++){//Nested for loop used to sort the array in ascending order
min=arr[i];
if(arr[i]<0||arr[i]>100){//If statement used to count how many numbers are <0 or >100
counter++;
}
for(int k=i+1;k<size;k++){
if(arr[k]<min){
arr[i]=arr[k];
arr[k]=min;
min=arr[i];
}
}
}
int *newSet=new int[size-counter];
for(int j=0;j<size;j++){
if(arr[j]>100||arr[j]<0){
//Do nothing
}else{
newSet[j]=arr[j];
}
}
delete newSet;
}
bool IntegerSet::validEntry(int a){
if(a<0||a>100){
return false;
}
return true;
}
void IntegerSet::inputSet(){
int a;
for(int i=0;i<100;i++){
cout<<"Enter an element(-1 to end)";
cin>>a;
if(a==-1){
cout<<"Entry complete";
return;
}
this->set[i]=a;
}
}
void IntegerSet::emptySet(){
for(unsigned int i=0;i<sizeof(this->set);i++){
this->set[i]=0;
}
}
IntegerSet IntegerSet::unionOfsets(IntegerSet a){
unsigned int *Union=new unsigned int[sizeof(this->set)+sizeof(a.set)];
for(unsigned int i=0;i<sizeof(this->set);i++){
*(Union+i)=this->set[i];
for(unsigned int h=0;h<sizeof(this->set);h++){
*(Union+(h+i))=a.set[h];
}
}
for(unsigned int j=0;j<sizeof(*Union);j++){
for(unsigned int z=j+1;z<sizeof(*Union);z++){
if(*(Union+j)==*(Union+z)){
*(Union+z)=0;
}
}
}
unsigned int newUnion[sizeof(*Union)];
for(unsigned int y=0;y<sizeof(*Union);y++){
if(*(Union+y)!=0&&y<sizeof(newUnion)){
newUnion[y]=*(Union+y);
}
}
IntegerSet c;
for(unsigned int w=0;w<sizeof(*Union);w++){
c.set[w]=newUnion[w];
}
delete Union;
return c;
}
IntegerSet IntegerSet::intersectionOfSets(IntegerSet a){
unsigned int *Intersect=new unsigned int[sizeof(this->set)+sizeof(a.set)];
int counter=0;
for(unsigned int i=0;i<sizeof(this->set);i++){
for(unsigned int j=0;j<sizeof(a.set);j++){
if(this->set[i]==a.set[j]){
*(Intersect+counter)=a.set[j];
counter++;
}
}
}
IntegerSet c;
for(unsigned int w=0;w<sizeof(*Intersect);w++){
c.set[w]=*(Intersect+w);
}
delete Intersect;
return c;
}
void IntegerSet::printSet(){
unsigned int min;
for(unsigned int i=0;i<sizeof(this->set)-1;i++){
min=this->set[i];
for(unsigned int k=i+1;k<sizeof(this->set);k++){
{
if(this->set[k]<min){
this->set[i]=this->set[k];
this->set[k]=min;
min=this->set[i];
}
}
}
cout<<"{";
for(unsigned int h=0;h<3;h++){
if(h==sizeof(this->set)-1){
cout<<this->set[h]<<"}";
}else{
cout<<this->set[h]<<",";
}
}
}
bool IntegerSet::isEqualTo(IntegerSet a){
unsigned int counter=0;
if(sizeof(a.set)==sizeof(this->set)){
for(unsigned int i=0;i<sizeof(this->set);i++){
for(unsigned int f=0;f<sizeof(a.set);f++){
if(this->set[i]==a.set[f]){
counter++;
}
}
}
}else{
return false;
}
if(counter==sizeof(this->set)){
return true;
}
return false;//Used to make sure this method always has something to return
}
void IntegerSet::insertElement(int a){
unsigned A=(unsigned)a;
if(!this->validEntry(a)){
cout<<"Invalid Insertion Attempt!";
}
unsigned int Inserted[sizeof(this->set)+1];
Inserted[sizeof(this->set)]=A;
for(unsigned int w=0;w<sizeof(Inserted);w++){
this->set[w]=Inserted[w];
}
}
void IntegerSet::deleteElement(int a){
unsigned A=(unsigned) a;
unsigned int *Delete=new unsigned int[sizeof(this->set)-1];int test=0;
if(!this->validEntry(a)){
cout<<"No value of: "<<a<<" exists in the set";
}
for(unsigned int z=0;z<sizeof(this->set);z++){
if(this->set[z]==A){
test++;
}
}
if(test==0){
cout<<"No value of: "<<a<<" exists in the set";
}
for(unsigned int i=0;i<sizeof(this->set)-1;i++){
*(Delete+i)=this->set[i];
}
for(unsigned int w=0;w<sizeof(*Delete);w++){
this->set[w]=*(Delete+w);
}
delete Delete;
}
And then there is my tester file, which is what allowed me to find the error
(IntSet.cpp)
//Driver program for class IntegerSet
#include <iostream>
using namespace std;
#include "IntegerSet.h"
int main(){
IntegerSet a,b,c,d;
cout<<"Enter set A:\n";
a.inputSet();
cout<<"\nEnter set B:\n";
b.inputSet();
c=a.unionOfsets(b);
d=a.intersectionOfSets(b);
cout<<"\nUnion of A nd B is:\n";
c.printSet();
cout<<"Intersection of A nd B is:\n";
d.printSet();
//Test if set A is equal to set B
if(a.isEqualTo(b)){
cout<<"Set A is equal to set B\n";
}else{
cout<<"Set A is not equal to set B\n";
}
//test insertion
cout<<"\nInserting 77 into set A...\n";
a.insertElement(77);
cout<<"Set A is now:\n";
a.printSet();
const int arraySize=10;
int intArray[arraySize]={25,67,2,9,99,105,45,-5,100,1};
//Use construct that receive an array of ints
//and the size of that array to create a set object
IntegerSet e(intArray,arraySize);
cout<<"\nSet e is:\n";
e.printSet();
cout<<endl;
}
Personally I feel like what caused this error was some sort of memory leak, although the glib c error isn't exactly telling me where it would be coming from like the compiler does. Also this error occurs right after the function b.inputSet() exits.
What the error says (it alternates between two messages I've noticed):
***glibc detected*** ./a.out: free(): invalid next size (normal):
***glibc detected*** ./a.out: double free or corruption (!prev):
You're doing lots of bad here.
Here's your definition of empty_set.
unsigned int empty_set[15];
And your default constructor accesses outside these bounds.
IntegerSet::IntegerSet(){
for(int i=0;i<100;i++){
empty_set[i]=0;
}
}
Your other constructor doesn't actually change anything inside the class.
Also this code
IntegerSet IntegerSet::unionOfsets(IntegerSet a){
unsigned int *Union=new unsigned int[sizeof(this->set)+sizeof(a.set)];
looks remarkably suspicious as sizeof(set) is not the number of elements in set, but the array length in bytes (15*sizeof(float)) - but if you switch to a variable length array it wont even be that... You'll need to track the set length separately. Or use a std::vector<int>, or better yet - why reinvent the wheel and use std::set<int>?

Difference between creating an array in constructor and declaration in c++

While I was trying to create an array in c++ class, there arose a problem while using the constructor. Here is the code:
int stacksize = 100;
int* buffer;
int stackpointer[3]= {-1, -1, -1};
public:
threestack(int stacksize_u)
{
int buffer_u[stacksize_u*3];
this->buffer = buffer_u;
this->stacksize = stacksize_u;
}
threestack()
{
int buffer_u[(this->stacksize)*3];
this->buffer = buffer_u;
}
This actually did not work. When I create the array in the declaration, however, it worked:
int stacksize = 100;
int buffer[300];
int stackpointer[3]= {-1, -1, -1};
Can anybody tell me what is wrong while I was using the constructor?
PSS: Here is the whole class and test program:
class threestack
{
int stacksize = 100;
int* buffer;
int stackpointer[3]= {-1, -1, -1};
public:
threestack(int stacksize_u)
{
int buffer_u[stacksize_u*3];
this->buffer = buffer_u;
this->stacksize = stacksize_u;
}
threestack()
{
int buffer_u[(this->stacksize)*3];
this->buffer = buffer_u;
}
bool push(int stacknum, int value);
bool pop(int stacknum);
int peek(int stacknum);
bool empty(int stacknum);
};
bool threestack::push(int stacknum, int value)
{
if(stackpointer[stacknum-1]+1 >= stacksize)
{
cout<<"Plz do not try to push to a full stack"<<endl;
// printf("stackpointer = %d\n", stackpointer[stacknum-1]);
return 0;
}
else
{
stackpointer[stacknum-1]++;
buffer[stackpointer[stacknum-1]+(stacknum-1)*stacksize] = value;
return 1;
}
}
int threestack::peek(int stacknum)
{
if(stackpointer[stacknum-1] < 0)
{
printf("No element in stack now.\n");
return 0;
}
else
{
printf("stackpointer = %d\n", stackpointer[stacknum-1]);
return buffer[stackpointer[stacknum-1]+(stacknum-1)*stacksize];
}
}
bool threestack::pop(int stacknum)
{
if(stackpointer[stacknum-1] < 0)
{
printf("Plz do not try to pop an empty stack.\n");
return 0;
}
else
{
stackpointer[stacknum-1]--;
}
return 1;
}
bool threestack::empty(int stacknum)
{
if(stackpointer[stacknum-1] < 0)
{
return true;
}
else
{
return false;
}
}
int main(int argc, const char * argv[])
{
threestack test;
test.push(1,5);
// test.pop(1);
// test.pop(1);
int i;
for(i=0; i<101; i++)
{
test.push(2, i);
printf("%d\n", test.peek(2));
}
cout<<endl;
printf("The top of stack 1 is %d\n", test.peek(1));
// std::cout << "Hello, World!\n";
return 0;
}
C++ arrays have a fixed size at compile time.
This is why your test module works - the size (=300) is known at compile time.
That's mandatory because the size of an array is in fact part of it's type, implying that
the type of int[1] is very different from int[2].
Yet it is not known when you kind of "dynamically" create the array in the constructor.
The way out is allocating dynamic memory using the new and delete [] operators.
Even better, try to use shared_ptr, unique_ptr or auto_ptr.
This
int* buffer;
is not a declaration of an array. It is a declaration of a pointer to int.
In constructor
threestack(int stacksize_u)
{
int buffer_u[stacksize_u*3];
this->buffer = buffer_u;
this->stacksize = stacksize_u;
}
all these two statements
int buffer_u[stacksize_u*3];
this->buffer = buffer_u;
are invalid. Firest of all sizes of arrays shall be constant expressions. Secondly you assign adrress of the first element of a local array to pointer buffer. After exiting from the constructor this address will be invalid because the local array will be destroyed.
You should either allocate dynamically array using operator new and assigning its value to data member buffer or use container std::vector instead of the dynamically allocated array.

Implementing a int stack in C++

I came across a exercise on the web, this is the text:
Write a class int_stack that will manage a stack of integers. The
integers values will be stored in a dynamically allocated array.
This class will propose the following member functions :
int_stack (int n) constructor that will dynamically allocate n
integers,
int_stack ( ) constructor allocating 20 integers,
~ int_stack ( ) destructor,
int empty ( ) the return value is 1 if the stack is empty, 0
otherwise,
int full ( ) the return value is 1 if the stack is full, 0 otherwise,
void operator < (int p) pushes (add) the p value on the stack,
int operator >(int p) returns (and remove) the value on the top of
the stack
I've tried to implement it, but the > (pull) operator won't work.
Here's my code:
int_stack.h
class int_stack
{
private:
int* stack;
unsigned int n, p;
void init(unsigned int n);
public:
int_stack(unsigned int n);
int_stack();
~int_stack();
int empty();
int full();
void operator <(int i);
int operator >(int i);
};
int_stack.cpp
#include "int_stack.h"
void int_stack::init(unsigned int n)
{
this->stack = new int[n];
this->p = 0;
}
int_stack::int_stack(unsigned int n)
{
this->init(n);
}
int_stack::int_stack()
{
this->init(20);
}
int_stack::~int_stack()
{
delete this->stack;
}
int int_stack::empty()
{
return (this->p == 0 ? 1 : 0);
}
int int_stack::full()
{
return (this->p == n-1 ? 1 : 0);
}
void int_stack::operator <(int i)
{
if (!this->full())
this->stack[p++] = i;
}
int int_stack::operator >(int i)
{
if(!this->empty())
return this->stack[p--];
return 0;
}
What am I doing wrong?
In addition to getting the indexing right, the class needs a copy constructor and an assignment operator. As written you'll get multiple deletes of the same data block:
int_stack s0;
int_stack s1(s0); // uh-oh
Both destructors will delete the array allocated by the constructor for s0.
There are several major flaws with you code:
Unless you want to resize the stack every time you push or pop something onto or off of it, respectively, you probably want to use a linked-list- or deque- style storage structure instead of a vector/array-style.
Overloading operator< and operator> to do what amounts to extraction and insertion is a terrible interface choice. I would urge against using operators for those operations:
void int_stack::push(int i)
{
// push an element onto the stack
}
int int_stack::pop()
{
// pop an element off of the stack
}
Because you are not implementing it as a linked-list or deque, when you go to push elements, you can (and eventually will) attempt to write outside the bounds of the memory you allocated.
Finally, you do not delete your stack properly. If you use new [], you must also use delete [].
The choice of interface is quite bad, but ignoring that fact consider what your members mean, in particular p. The index p refers to the location above the last added element. When you return the value in the pop operation you are reading the value from that location, but that location does not have a value:
int int_stack::operator >(int i)
{
if(!this->empty())
return this->stack[p--]; // <-- predecrement!
return 0;
}
Regarding the interface, operator< and operator> are unnatural choices for the push and pop operations. When someone reads in code s < 5 they interpret that you are comparing s with 5, not inserting an element into the stack s. That is going to be the source of confusion.
Worse than operator< is operator> defined as int operator>(int). User code to read a value will end up looking as:
value = s > 5;
That looks like comparing s to 5, and storing the result into value. Moreover, the actual behavior is completely independent on the argument 5, the same operation can be spelled as s > -1 or even s > 5.3
Here is the working implementation I came up with.
It implements a copy constructor and the assignment operator.
Also, the indexing works, and the interface has changed from the < and > operators to two simple push(int) and int pop() functions.
It throws exceptions when you try to push/pop over the boundaries.
int_stack.h
#include <exception>
class int_stack
{
private:
int* stack;
unsigned int n, p;
void init(unsigned int n);
void copy(int_stack& other);
public:
int_stack(unsigned int n);
int_stack();
int_stack(int_stack& other);
int_stack& operator=(int_stack& other);
~int_stack();
int empty();
int full();
void push(int i);
int pop();
class OutOfBoundariesException: public std::exception {};
};
int_stack.cpp
#include "int_stack.h"
void int_stack::init(unsigned int _n)
{
n = _n;
stack = new int[n];
p = 0;
}
int_stack::int_stack(unsigned int n)
{
init(n);
}
int_stack::int_stack()
{
init(20);
}
int_stack::int_stack(int_stack& other)
{
copy(other);
}
int_stack& int_stack::operator=(int_stack& other)
{
copy(other);
return *this;
}
void int_stack::copy(int_stack& other)
{
n = other.n;
p = other.p;
stack = new int[n];
for (unsigned int i = 0; i < n; i++)
stack[i] = other.stack[i];
}
int_stack::~int_stack()
{
delete[] stack;
}
int int_stack::empty()
{
return (p == 0 ? 1 : 0);
}
int int_stack::full()
{
return (p == n ? 1 : 0);
}
void int_stack::push(int i)
{
if (!full())
stack[(++p)-1] = i;
else
throw new OutOfBoundariesException;
}
int int_stack::pop()
{
if (!empty())
return stack[(p--)-1];
else
throw new OutOfBoundariesException;
return 0;
}

Unable to decipher "error: expected unqualified-id before 'int'"

I've been looking around and haven't come up with any tangible solutions. It sounds like it is looking for a default constructor instead of the one in place but I have one below. Moving it up as the first listed constructor didn't change the error messages so I'm wrong about that. Here's the full error message (using jGRASP):
In file included from intset.h:47:0,
from IntSet.cpp:1:
IntSet.cpp:12:11: error: expected unqualified-id before 'int'
IntSet(int a, int b, int c, int d, int e) {
^
IntSet.cpp:12:11: error: expected ')' before 'int'
Here's the IntSet.cpp code:
#include "intset.h"
//#include <algorithm>
//#include <iostream>
int size;
const int MAXSIZE = 25000;
bool set[MAXSIZE];
const int SENTINEL = -1;
//Constructors
IntSet(int a, int b, int c, int d, int e) {
size = a;
if(b > size) {
size = b;
}
if(c > size) {
size = c;
}
if(d > size) {
size = d;
}
if(e > size) {
size = e;
}
set = new bool[size];
for(int i = 0; i <= size; i++) {
if(i == a || i == b || i == c || i == d || i == e) {
insert(i);
} else {
remove(i);
}
}
}
IntSet(int a, int b, int c, int d) {
IntSet(a, b, c, d, -1);
}
IntSet(int a, int b, int c) {
IntSet(a, b, c, -1, -1);
}
IntSet(int a, int b) {
IntSet(a, b, -1, -1, -1);
}
IntSet(int a) {
IntSet(a, -1, -1, -1, -1);
}
//Copy constructor
IntSet(const IntSet& x) {
size = x.size;
for (int i = 0; i <= x.size; i++ ) {
set[i] = x.set[i];
}
}
//Destructor
~IntSet()
{
//for(int i = this.length(); i >= 0; i--) {
// this[i]
//}
}
////////////////////////
bool insert(int a) {
if(a <= size && a >= 0) {
set[a] = true;
return true;
}
else if(a >= 0) {
//removed "new" from line below
IntSet temp = IntSet(a);
&this += temp;
set[a] = true;
return true;
}
return false;
}
bool remove (int a) {
if (isInSet(a)) {
set[a] = false;
return true;
}
return false;
}
bool isEmpty() {
bool retVal = true;
for (int i = 0; i <= size; i++) {
if (set[i] == true) {
retVal = false;
}
}
return retVal;
}
bool isInSet (int a) {
if (set[a]){
return true;
}
return false;
}
/////////////////////////////////////////////
IntSet operator + (IntSet a) {
IntSet c = IntSet(max(size, a.size));
for (int i = 0; i <= c.size; i++) {
if (set[i] || a.set[i]){
c.set[i] = true;
}
else {
c.set[i] = false;
}
}
return c;
}
IntSet operator * (IntSet a) {
IntSet c = IntSet(max(size, a.size));
for (int i = 0; i <= c.size; i++) {
if (set[i] && a.set[i]) {
c.set[i] = true;
}
else {
c.set[i] = false;
}
}
return c;
}
IntSet operator - (IntSet a) {
IntSet c = IntSet();
c.size = 0;
for (int i = 0; i <= size; i++) {
if (set[i] && !a.set[i]) {
c.set[i] = true;
}
else {
c.set[i] = false;
}
c.size++;
}
return c;
}
IntSet operator = (const IntSet a) {
return IntSet(a);
}
IntSet operator += (IntSet a) {
return IntSet(operator+(a));
}
IntSet operator *= (IntSet a) {
return IntSet(operator * (a));
}
IntSet operator -= (IntSet a) {
return IntSet(operator - (a));
}
IntSet operator == (const IntSet a) const{
for(int i = 0; i < size; i++) {
if(set[i] != a.set[i]) {
return false;
}
}
return true;
}
IntSet operator != (IntSet a) {
for(int i = 0; i < size; i++) {
if(set[i] != a.set[i]) {
return true;
}
}
return false;
}
IntSet operator << (IntSet a) {
cout << "{";
for(int i = 0; i < size; i++) {
if(set[i]) {
cout << " " << i;
}
}
cout << "}";
}
IntSet operator >> (IntSet a) {
int index;
while(cin >> index && index != SENTINEL) {
insert(index);
}
}
Here is the attached intset.h code:
#ifndef INTSET_H
#define INTSET_H
#include <iostream>
#include <algorithm>
using namespace std;
class IntSet {
public:
//Constructors
IntSet();
IntSet(int);
IntSet(int, int);
IntSet(int, int, int);
IntSet(int, int, int, int);
IntSet(int, int, int, int, int);
IntSet(const IntSet&); // M: Added the &; must be a pointer or reference
~IntSet();
//Overloaded Operators M: Added 'IntSet' in front of the word 'operator.'
// It was required syntax.
IntSet operator+(IntSet);
IntSet operator*(IntSet);
IntSet operator-(IntSet);
IntSet operator=(IntSet);
IntSet operator+=(IntSet);
IntSet operator*=(IntSet);
IntSet operator-=(IntSet);
IntSet operator==(IntSet);
IntSet operator!=(IntSet);
IntSet operator<<(IntSet);
IntSet operator>>(IntSet);
//Functions
bool insert(int);
bool remove(int);
bool isEmpty();
bool isInSet(int);
private:
const int MAXSIZE;
int size;
bool set[];
const int SENTINEL;
};
#include "IntSet.cpp"
#endif
I haven't had much experience with header files so it wouldn't surprise me if I formatted something incorrectly but I'm looking at plenty of other samples provided by the professor and there isn't anything unusual about mine. I thought maybe it had something to do with the order listed in the .h file and that I wasn't following the same exact order in the .cpp but nothing changed when I had everything listed in the same order.
There is a lot that is wrong with your code. We are going to have to jump around a bit between the header and the implementation. Ready?
In your header you do this:
class IntSet {
/* stuff */
private:
bool set[];
};
First of all, the name set is a bad choice: it is the name of a class in namespace stdw which you are importing by having using namespace std in your header file. This can be confusing at best.
More importantly, the syntax bool set[] isn't correct in this context. Even if your compiler allows it, it's an extension. Who knows what it does and how it will behave on other compilers? Avoid it.
If you want to declare an array, declare an array. If you want to declare a pointer, declare a pointer. Just remember: an array isn't a pointer.
Unfortunately you don't, becase later on in your code you do this:
set = new bool[size];
What is this supposed to do? set isn't a pointer, it's some kind of array, and you cannot assign a pointer to an array.
Now, we get to the second problem: you declare some member variables for your class, in your header file:
class IntSet {
/* some stuff here */
private:
const int MAXSIZE;
int size;
bool set[];
const int SENTINEL;
};
Then in your implementation you have the following code floating up at the top:
int size;
const int MAXSIZE = 25000;
bool set[MAXSIZE];
const int SENTINEL = -1;
I don't think that this does what you think it does. It seems that your intention is to initialize those variables, but that's not what happens. Remember, those variables only exist as members variables that belong to a particular instance of a class, and they are not "free-standing". So what's happening here?
Well, this declares all these variables again, so you have variables called MAXSIZE, size, set and SENTINEL that are valid anywhere in that translation unit (i.e. the .cpp file), independent of the member variables in the class.
This, of course, means that the member variables with those names aren't initialized (well, except set which you assign a pointer to, which we already know is wrong). This will cause your code to exhibit undefined behavior. After all, the value of an uninitialized variable can be anything at all.
If your intention had been to initialize the class members, then you should remove that code and initialize those variables in your constructor(s):
IntSet::IntSet(int a, int b, int c, int d, int e)
: size(a), MAXSIZE(25000), SENTINEL(-1)
{
/* whatever*/
}
Notice, by the way, how I used IntSet:: in front of the constructor name? This is called the scope resolution operator. Remember, there is no constructor called IntSet. The constructor belongs to a class, which is called IntSet, and outside of that class, it's proper name is IntSet::IntSet. A small example may help:
class Test
{
int Length;
public:
/* notice how inside the class, you only need Test
* when providing a body for the constructor. This
* makes sense. You know which class you inside of.
*/
Test()
: Length(0)
{
}
Test(int len);
};
/* Now we are outside the class. We need to help
* the compiler out and tell it what class the
* function belongs to.
*/
Test::Test(int len)
: Length(len)
{
}
A tangential point as to do with the names that you are using. What's a? Why do you use a to initialize something called size? You should choose meaningful variables names that help document the code so that when you have to read it back your head doesn't explode.
Another tangential point is that if variables like MAXSIZE and SENTINEL are going to be shared between all instances of the class, then, for future reference, you should probably consider making them static class members.
Lastly, you have this bit of code in your header file
#include "IntSet.cpp"
This is, almost certainly, not correct. You should never do this (there may be some who think that there are exceptions, but don't learn bad habits at this point. When you know enough to stumble on this legitimately, then you will know enough to determine whether it's the right thing to do or not).
What makes it worse is that your implementation file contains:
#include "IntSet.h"
Think about what you are doing here: when the compiler is processing the file IntSet.h you are telling to also process the file IntSet.cpp. The file IntSet.cpp tells the compiler to process the file IntSet.h. Which tells the compiler to process the file IntSet.cpp. And so on and so forth.
Generally speaking, implementation files (.cpp) will include header files. Header files will only include other header files.
There are a few other issues, but you should probably fix all these things, and then, if you are still having issues, post a new question and we can go from there.
Good luck!
You need to put the name of the class and :: before defining a member function.
IntSet::IntSet(int a, int b, int c, int d, int e) {
//^^^^^^^^
//here
Do the same with the other constructors, the operators and methods.