I have defined a stack class containing methods for pushing and popping values onto the stack.
In the tester file (shown below), after running it, an occur occurs & the program crashes. I know this is due to the function f, which creates an error as two pointers are pointing to the same location in memory. If i comment out the line f(s) when the function is called, the pop & push functions work correctly and the output is correct.
To fix this error, I have been asked to ; Create a copy constructor for this class to fix the above problem.
I'm not really familiar with this, so any help would be appreciated in how to do this. Thanks
Main Test file
#include "Stack.h"
#include <iostream>
#include <string>
using namespace std;
void f(Stack &a) {
Stack b = a;
}
int main() {
Stack s(2); //declare a stack object s which can store 2 ints
s.push(4); //add int 4 into stack s
//s = [4]
s.push(13); //add int 13 into stack s
//s = [4,13]
f(s); //calls the function f which takes in parameter Stack a , and sets Stack b = to it.
//error here - as 2 pointers point to the same location in memory !
cout << s.pop() << endl; //print out top element(most recently pushed) element.
//so should output 13
return 0;
}
Header File Code
#ifndef STACK_H
#define STACK_H
class Stack {
public:
//constructor
Stack(int size);
//destructor
~Stack();
//public members (data & functions)
void push(int i);
int pop();
private:
//private members (data & functions)
int stck_size;
int* stck;
int top;
};
#endif
Stack.cpp Code
#include "Stack.h"
#include <iostream>
#include <string>
using namespace std;
Stack::Stack(int size){
stck_size = size;
stck = new int[stck_size];
top = 0;
}
Stack::~Stack() {
delete[] stck;
}
void Stack::push(int i) {
if (top == stck_size) {
cout << "Stack overflow." << endl;
return;
}
stck[top++] = i;
}
int Stack::pop() {
if (top == 0) {
cout << "Stack underflow." << endl;
return 0;
}
top--; //decrement top so it points to the last element istead of the empty space at the top.
return stck[top];
}
Copy constructor here is pretty quick-and dirty:
Stack::Stack(const Stack & src):
stck_size(src.stack_size),
stck(new int[stck_size]),
top(src.top) //Member Initializer List
{
// copy source's stack into this one. Could also use std::copy.
// avoid stuff like memcpy. It works here, but not with anything more
// complicated. memcpy is a habit it's just best not to get into
for (int index = 0; index < top; index++)
{
stck[index] = src.stck[index];
}
}
Now that you have a copy constructor, you're still likely screwed because the Rule of Three has not been satisfied. You need operator=. And this is easy because the copy construct and the copy and swap idiom makes it easy.
Basic form:
TYPE& TYPE::operator=(TYPE rhs) //the object to be copied is passed by value
// the copy constructor makes the copy for us.
{
swap(rhs); // need to implement a swap method. You probably need one
//for sorting anyway, so no loss.
return *this; // return reference to new object
}
Your copy constructor should look like this:
Stack::Stack(const Stack &r) {
stck_size = r.stck_size;
stck = new int[stck_size];
top = r.top;
memcpy(stck, r.stck, top*sizeof (int));
}
Related
I would like to ask 2 question about this code. Where I just try to simulate a stack.
Stack.h
#pragma once
namespace stackandqueue {
class Stack
{
private:
int index;
int *stackdata;
public:
Stack();
~Stack();
void push(int val);
int pop();
int top();
bool isEmpty();
};
}
Stack.cpp
#include "stdafx.h"
#include "Stack.h"
namespace stackandqueue {
Stack::Stack() : index{ 0 }
{
stackdata = new int[index];
}
Stack::~Stack()
{
delete[] &stackdata;
}
void Stack::push(int val) {
stackdata[index] = val;
index++;
}
int Stack::pop() {
int val = stackdata[index];
index--;
return val;
}
int Stack::top() {
return stackdata[index];
}
bool Stack::isEmpty() {
return index == 0;
}
}
Meaning is to let me create
Stack stack;
And then it initilizes a dynamic array with 0 as first index and that let me push, pop, top values.
First question:
Why am I having unresolved symbols for method definitions?
Second question:
About 'stackdata', you find is the right way if I want to declare an "array" with dynamic size for this behaviour?
I'm open for improvements and best practices. Im used to programming languagesbut I've never delved into c ++ and I don't want to have bad practices. So you see I am taking it from the begining.
Thanks.
I post solution reached with your help that maybe helps someone.
class Stack
{
private:
int index;
int* stackdata;
public:
Stack(int size);
~Stack();
void push(int val);
int pop();
int top();
bool isEmpty();
};
Stack::Stack(int size)
: index {0}, stackdata{new int[size]}
{
}
Stack::~Stack()
{
delete[] stackdata;
}
void Stack::push(int val) {
stackdata[index] = val;
index++;
}
int Stack::pop() {
index--;
return stackdata[index];
}
int Stack::top() {
return stackdata[index-1];
}
bool Stack::isEmpty() {
return index == 0;
}
There are several problems with this.
An array, dynamically allocated or otherwise, is not a stack/queue/vector. You're creating literally 0 ints. All of your element accesses after that have undefined behaviour. You need your array to grow, i.e. be a vector, e.g. std::vector.
delete[] &stackdata has the wrong level of indirection. You meant delete[] stackdata. You were trying to delete the pointer which was not dynamically allocated.
You're missing copy/move constructors and copy/move assignment operators so as soon as you transport a Stack anywhere it will explode. (The original instance will do a delete[] on the same pointer that the copied/moved instances will!) Read about the rule of three/five/zero.
Other than that, it looks like a stack.
The problem you don't have here is an undefined reference, which is funny because that's the only one you asked about. :) If you do indeed have such a thing, it's likely a problem with your build system (failing to compile that source file), which we cannot see.
I'm trying to figure out why I'm getting a seg-error from my singly linked list implementation.
I create an object of type Deque called dq1, compiler calls the destructor for it since the program is done - destructor calls remove_front() which deals with some move()'s for the head. I believe this is where the problem lies but I can't seem to figure out where exactly it is.
Debugger Info - Dont know what to make of this?
#0 0x4013ea std::unique_ptr<Node, std::default_delete<Node> >::get(this=0x8) (/usr/include/c++/6/bits/unique_ptr.h:305)
#1 0x401586 std::unique_ptr<Node, std::default_delete<Node> >::operator bool(this=0x8) (/usr/include/c++/6/bits/unique_ptr.h:319)
#2 0x40140b std::operator!=<Node, std::default_delete<Node> >(std::unique_ptr<Node, std::default_delete<Node> > const&, decltype(nullptr))(__x=<error reading variable: Cannot access memory at address 0x8>) (/usr/include/c++/6/bits/unique_ptr.h:670)
#3 0x401132 Deque::size(this=0x7fffffffe520) (Deque.cpp:75)
#4 0x4010f2 Deque::empty(this=0x7fffffffe520) (Deque.cpp:66)
#5 0x4016dd main() (/test.cpp:12)
Deque.cpp
#include "Deque.h"
#include <iostream>
#include <memory>
#include <utility>
#include <stdexcept>
using std::cout;
using std::endl;
using std::move;
Deque::~Deque()
{
while (!empty()) remove_front();
}
void Deque::insert_front(int a)
{
std::unique_ptr<Node> new_node;
new_node->val = move(a);
new_node->next = move(head); // head is wiped.
head = move(new_node); //head is init. with new_node val*/
}
int Deque::remove_front()
{
if (empty()) {throw std::runtime_error(std::string("Empty"));};
std::unique_ptr<Node> old;
int return_value = head->val;
old = move(head);
head = move(old->next);
delete &old;
return return_value;
}
bool Deque::empty() const
{
return (size() == 0);
}
int Deque::size() const
{
int size_val = 0;
const Node* p = head.get();
while ( p != NULL)
{
size_val++;
p = p->next.get();
}
return size_val;
}
test.cpp
#include <iostream>
#include "Deque.h"
using std::cout;
using std::endl;
int main()
{
Deque dq1;
return 0;
}
deque.h
#include "Node.h"
#include <memory>
class Deque{
public:
Deque() = default;
Deque(const Deque&);
~Deque(); //must use constant space
Deque& operator=(const Deque&){return *this;};
void insert_front(int);
int remove_front();
bool empty() const;
private:
friend Node;
std::unique_ptr<Node> head ;
std::unique_ptr<Node> tail ;
};
Node.h
#include "Node.h"
std::ostream& operator<<(std::ostream& out, const Node& n) {
return out << &n << ": " << n.val << " -> " << n.next.get();
}
You have UB right here:
std::unique_ptr<Node> new_node;
new_node->val = move(a);
you create a new pointer that is default initialized (points to nullptr) and you dereference it. You should initialize it with std::make_unique if you have C++14 or later or just initialize it with new:
std::unique_ptr<Node> new_node = std::make_unique<Node>(); // C++14 or later
std::unique_ptr<Node> new_node( new Node ); // pre C++14
This line also has issue:
delete &old;
this line does not make any sense. You get address of pointer itself, which is created as local variable and try to delete it. If you tried to delete data, where old points to, that is ether wrong - whole point of std::unique_ptr is to do that automatically.
This member:
std::unique_ptr<Node> tail ;
this is wrong by design, though you do not seem to use it in your code. This assumes you are going to have multiple std::unique_ptr to point to the same object. But this pointer is for unique ownership.
You seem to have issue in Deque::size() as well, but without seeing source it is impossible to say what is wrong there.
In your destructor you do not need to do anything (though it would not harm if other methods are implemented properly) - std::unqiue_ptr will destroy all data recursively.
i have a program with 3classes.
first one is for defining a node(my node is an array with 9 elements) - 2nd one contains some functions - 3rd is defining a static stack(I have a stack with 100members that each member is an array with 9members)
suppose that in main(), I call one of the functions from 2nd class(for example expand() ). expand function is supposed to push a node into stack(push into UN) and update the stack pointer. After that for example I want to have access to top node of stack and pop that node using main(). but I'm successful. when I watch the UN and top node through debug tool, I see that their amount is being reset after each push(stack doesn't accept new elements). whats wrong?
here is some parts of code that is needed:
#include<iostream>
using namespace std;
#define max 100
class node
{
public:
int node_n[9];
friend class func;
friend class stack;
};
node n;
class node;
class func
{
public:
func();
void expand(node,stack);
friend class stack;
};
class node;
class stack
{
private:
int sp;//stack pointer
public:
node un[max];//saves expanded noded(children)
stack();
int isempty(); //this will show whether stack is empty or not
int isfull(); //this will show whether stack is full or not
void push(node);
node pop();
};
//****************************
stack::stack()
{
sp=-1;
}
//****************************
int stack::isempty()
{
if(sp==-1)
return true;
else
return false;
}
//****************************
int stack::isfull()
{
return sp==max-1;
}
//****************************
node stack::pop() //un=un-[n]
{
for(int k=0;k<=8;k++)
n.node[k]=un[sp].node[k];
sp--;
return n;
}
//****************************
void stack::push(node n ) //un=un+{x1....xn}
{
sp++;
for(int k=0;k<=8;k++)
un[sp].node[k]=n.node[k];
}
//****************************
void func::expand(node n,stack st)
{
if ( n.node_n[0]==0 )
{
if(n.node_n[1]==0)
{
n.node_n[0]=1;
n.node_n[1]=1;
st.push(n);
.
.
.
//******************************
int main()
{
func b;
stack st;
node n2;
node s; //initial state
node g; //goal state
for(int h=0;h<=8;h++)
{
s.node[h]=0;
g.node[h]=1;
}
//n2=s;
st.push(s);
Lable1:
n2=st.pop();
b.expand(n2,st);
goto Lable1;
system("pause");
return(0);
}
This function
void func::expand(node n,stack st)
is taking the st parameter by value, meaning that it has its own copy of st and any changes it makes will only affect that copy.
What you probably want is to pass st by reference, so that the function can make changes to the original passed in object. To do this, change the function declaration and definition to:
void func::expand(node n,stack &st)
When I try to run my code, it show me debug assertion failed .Any one can help me, I am doing stack list,in the header file, I create a struct has three variable, string * s, int numoflength, stackFrame * next
void Stack::push(string& s)
{
StackFramePtr temp_ptr;
temp_ptr=new StackFrame;
temp_ptr->str=new string[s.size()];
(temp_ptr->str)[0]=s;
cout<<temp_ptr->str[0]<<endl;
temp_ptr->num_char=sizeofstring(s);
if(empty())
{
top=temp_ptr;
temp_ptr->next=NULL;
}
else
{
temp_ptr->next=top;
top=temp_ptr;
}
}
this is my code about push I think maybe those errors because of this function.
string Stack::pop()
{
if(empty())
exit(1);
string * name;
StackFramePtr temp;
temp=top;
name=top->str;
top=top->next;
delete temp;
return *name;
}
#include <iostream>
#include "stack.h"
#include <string>
using namespace std;
int main()
{
string str1="to";
string str2="hi";
string str3="food";
string str4="ba";
string str5="ti";
string str6="zhilong";
Stack s;
s.push(str1);
s.push(str2);
s.push(str3);
s.push(str4);
s.push(str5);
s.push(str6);
cout<<s;
system("pause");
return 0;
}
when I try to run this main function it give me debug failure, anyone can help me? thanks very much
class Stack
{
public:
Stack();
//Default Constructor used to create an empty Stack object.
~Stack();
//Destructor for Stack objects.
void push(string& str);
string pop();
bool empty();
//Checks to see if the Stack is empty. Returns true if empty, else returns false.
//Stack remains unchanged after function call.
friend ostream &operator<<(ostream & out_stream, Stack & mystack);
friend istream &operator>>(istream & in_stream, Stack & mystack);
private:
StackFramePtr top; // Points to the top of the stack;
};
ostream &operator<<(ostream & outs, Stack & sta)
{
if(sta.empty())
exit(1);
else
{
StackFramePtr read;
read=sta.top;
while(read!=NULL)
{
outs<<"string = "<<read->str[0]<<endl;
outs<<" number of charcter is" <<read->num_char;
read=read->next;
outs<<endl<<endl;
}
}
return outs;
}
In push you allocate an array of string, and assign that to the str member of Stack. In pop you copy str to name, then delete temp which (I'm assuming) will delete the array that name is now pointing in to. Lastly you dereference this dangling pointer and access memory that has already been freed.
To fix this, declare name as just a string, rather than a pointer to string, then set name=*top->str or name=top->str[0].
I have following code:
/* Example OOPBEI03.CPP */
#include <iostream>
using namespace std;
typedef char item;
class stack
{
private:
int p;
protected:
item *st;
public:
stack(int m=100)
{
st = new item[m];
p = 0;
}
~stack()
{
delete [] st;
}
void push(item v)
{
st[p++] = v;
}
item pop()
{
return st[--p];
}
int empty()
{
return !p;
}
};
class queue : public stack
{
private:
int q;
item *qp;
public:
queue(int m=50):stack(m)
{
q = 0;
qp = st;
}
~queue()
{
delete qp;
}
item deque()
{
return qp[q++];
}
};
int main()
{
stack s(50);
queue q(20);
s.push('a');
q.push('b');
s.push('c');
q.push('d');
cout<<"pop "<<s.pop()<<endl;
cout<<"pop "<<s.pop()<<endl;
cout<<"deque "<<q.deque()<<endl;
cout<<"deque "<<q.deque()<<endl;
cout<<"empty queue? "<<q.empty()<<endl;
cout<<"empty stack? "<<s.empty()<<endl;
getchar();
return 0;
}
I get at the end of main() in Visual Studio following error: "Debug Assertion Failed! ... _BLOCK_TYPE_IS_VALID(pHead->nBlockUse)".
If I uncomment the delete operation either in the destructor of the class queue or stack (I uncomment only one operation!), I have no problems.
How can I solve this?
Deleting qp should me the same as newing (it's term of mine))).
delete [] qp;
^^
But in this particular case deleting qp should be removed at all
you're deleting the pointer both in the stack base class and in the queue derived class.
let your stack class handle the ownership, don't delete it also in queue
by the way you should make copy construction and copy assignment private, or else handle it (known as the "rule of three"); otherwise these classes can easily be used in ungood ways...
in code that isn't just for learning, just use std::stack and std::queue instead of implementing such classes yourself
std::stack and std::queue are class templates with customizable underlying container type