Passing object by value and modifying it in C++ - c++

The book I'm using wants me to implement LIFO stacks using constructors in C++. The first implementation is fairly easy because it wants me to pass the object in a function by reference (so the code below has an additional & in pushexternal function).
However, I don't know how to properly implement the second version of it. It wants me to make it by passing the object by value. Therefore, it creates a copy of the object and after using a push function on a stack, the pushed element is gone. I don't know how to properly do it when passing it by value. I was thinking about using a copy constructor somehow, but I've tried it and it doesn't seem to work...
This is the code that is written in the book. I'm not supposed to modify it, I can only write my own class / additional functions:
void pushexternal(Stack s, int a) {
s.push(a);
}
int main() {
Stack s;
s.push(0);
s.push(1);
s.push(2);
pushexternal(s, 3);
pushexternal(s, 4);
return 0;
}
And this is a part of my implementation:
#include <iostream>
using namespace std;
class Stack {
public:
int ind;
int * arr;
Stack()
{
arr = new int[25];
ind = -1;
}
~Stack()
{
delete [] arr;
}
void push(int val)
{
arr[++ind] = val;
cout << "Added " << arr[ind] << " to " << ind << endl;
}
};
I'm aware that passing by value is not recommended here, but I'm really wondering how can I make it work properly when pass by value is mandatory. The only thing that comes to my mind is writing some kind of a copy constructor...?
Of course, my code doesn't work here as it makes a copy that is supposed to push a variable, but when passing by value, it's gone when it exits the function...
The results of this program should look like this:
Added 0 to 0
Added 1 to 1
Added 2 to 2
Added 3 to 3
Added 4 to 4

If you were to allocate an extra member in your arr member, you could then use arr[0] instead of ind as your index. That way, even if your stack object is copied by value, the arr pointer will still point to the same memory.
Similar, possibly more complex solutions exist, involving having your object contain a pointer to a structure with both ind and arr in it.

Related

Output error dynamically allocating class objects into a queue template

#include <iostream>
#include "QueueAr.h"
class Test {
int val;
public:
Test(int v)
{val = v;};
int getVal()
{return val;};
};
using namespace std;
int main(int argc, char **argv)
{
Queue<Test*> testStack(4);
for(int i = 0; i < 4; i++) {
Test *t = new Test(5);
testStack.enqueue(t);
delete t;
}
while(!testStack.isEmpty())
cout << (testStack.dequeue())->getVal() << endl;
return 0;
}
So I'm trying to play with the idea of declaring a template class with a data type that is programmer-defined. I decided to go a queue implementation made by the author of my data structures book as the template class.
Now I'm trying to feed some values into it.
I started by creating a Queue object whose data type is a pointer variable to my own class Test. I used a pointer variable because Queue<Test> wasn't working properly for some reason. Next, I came up with the above for loop to make an attempt at initializing, but when I dequeue and display the values, it returns all of them as zero, despite sending 5 to Test's constructor four times in the loop. I believe it might have something to do with the loop, or Test*, but I'm not entirely sure.
Does anyone know what might be wrong here? Thank you in advance.
Also, if anyone needs it, here are the links for the header file "QueueAr.h" and its member functions
https://github.com/rweichler/ecs60/blob/master/p2/src/QueueAr.h
https://github.com/rweichler/ecs60/blob/master/p2/src/QueueAr.cpp
After storing the pointer to Test in your Queue you delete the pointer. This frees the memory and leaves the pointer stored in the Queue dangling, pointing at freed memory. When you dereference this pointer to display the value you can get anything.

c++'s temporary objects when inserted to a vector

I'm trying to make this code work, but the object keep getting destroyed...
I've found that it has to do with the object being copied to the vector, but can't find any way to prevent it...
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Obje
{
private:
static int instances;
int id;
public:
static int getInstances();
void getId();
virtual void myClass();
Obje(int auxId);
~Obje();
};
int Obje::instances = 0;
int Obje::getInstances()
{
return instances;
}
Obje::Obje(int auxId)
{
this->id = auxId;
cout << "Obje Created." << endl;
Obje::instances++;
}
Obje::~Obje()
{
cout << "Obje Destroyed." << endl;
Obje::instances--;
}
void Obje::myClass()
{
cout << "Obje." << endl;
}
void Obje::getId()
{
cout << this->id << endl;
}
int main()
{
vector <Obje> list;
Obje *a = new Obje(59565);
list.push_back(*a);
Obje *b = new Obje(15485);
list.push_back(*b);
for(vector<Obje>::iterator it = list.begin(); it != list.end(); ++it)
{
it->getId();
}
return 0;
}
It Generates this output:
Obje Created.
Obje Created.
Obje Destroyed.
59565
15485
Obje Destroyed.
Obje Destroyed.
What does it mean the T(const T& new); i've saw as fix for this?
First of all, it is a bad practice to allocate an object in heap without using smart pointers and forgetting to delete it. Especially, when you are creating it just to make a copy of it.
list.push_back(*a); creates a copy of *a in vector. To create an item in vector without copying another item, you can do list.emplace_back(/*constructor parameters*/);, which is available from c++11. (see http://en.cppreference.com/w/cpp/container/vector/emplace_back)
So, to make the result behavior match your expectations, you should go
vector <Obje> vec;
vec.emplace_back(59565);
vec.emplace_back(15485);
for(const auto & item : vec)
{
item.getId();
}
By the way, it is also a quite bad practice to call a vector as a list, as a list is a different container type and reading such code may be confusing a bit. I guess, I am starting being annoying, but it is better to call method getId as showId as now it returns nothing.
Regarding the use of heap, new and pointer, see my comment in your question.
Regarding the issue object was destroyed, the vector maintains an internal buffer to store object. When you push_back new object to the vector, if its internal buffer is full, it will (the stuff which will be executed when exception occurs won't be mentioned here.):
allocate new internal buffer which is big enough to store its new data.
move data from old internal buffer to new internal buffer.
destroy old buffer.
Hence, your object will be destroyed and copied to new location in this case, hence copy constructor will make it clearer to you.
P/S: AFAIK, some compilers move its data by memmove or std::move

Assertion error when passing object by value -- it is my copy constructor?

everyone!
I just finished writing a 2-D maze (Class is an ADT titled "Maze"--how original) that uses dynamic memory allocation. I'm passing the Maze to a method of another class I've entitled "MazeSolver," which uses recursion and backtracking to solve the maze. Good news is my code compiles wonderfully when I pass the object by reference. News that I don't know if is good or bad is that I get an assertion error if I try to pass the Maze to MazeSolver by value.
Given that the error occurs only when I pass by value, I can only assume it has something to do with my copy constructor. Before going any further, here's some info on the code:
Maze is composed of squares. Each square is represented by a struct called SquareData.
struct SquareData
{
//data fields for the struct (NO POINTERS)
}
I've decided to represent the entire maze with a vector of SquareData pointers (this vector is in private section of the class "Maze").
vector<SquareData*> squares;
Implementation of my destructor looks like this (that last call referencing a Player class is just eliminating a dangling pointer I have declared as a static variable for that class, which I have pointing at the maze. I don't think it's important considering the question, but I am new to C++ after all and one of you may think it might be, so I've included it for "hmmms"):
// clears maze of its contents
void Maze::clear() {
int totalSquares = squares.size();
for (int loopVar = 0; loopVar < totalSquares; loopVar++)
{
delete squares[loopVar]; // deallocate memory by deleting the square structure
squares[loopVar] = nullptr; // eliminate dangling pointer
} // vector takes care of itself
} // end clear
Maze::~Maze(){
//clear the maze of contents (vector is full of pointers whose memory is on the heap)
clear();
//vector safe to deallocate itself now
Player::setMaze(nullptr); // remove the pointer from player
}
I've declared the copy constructor in header as follows:
/** Copy Constructor */
Maze(const Maze& myMaze);
with attempted implementation:
/** copy constructor */
Maze::Maze(const Maze& myMaze){
/** Initialize Constants */
mazeLength = myMaze.mazeLength;
mazeWidth = myMaze.mazeWidth;
exitRow = myMaze.exitRow;
exitCol = myMaze.exitCol;
entRow = myMaze.entRow;
entCol = myMaze.entCol;
/** copy the vector of pointers*/
for (int loopVar = 0; loopVar < myMaze.squares.size(); loopVar++)
{
squares.push_back(myMaze.squares[loopVar]);
}
} // end copy constructor
Here's how I attempted to understand what the problem was doing:
I wrote this vector display function in for my Maze class.
void Maze::vectorDisplay() const {
for (int loopVar = 0; loopVar < squares.size(); loopVar++)
{
cout << "Vector Index: " << loopVar << endl;
cout << "Pointer: " << squares[loopVar] << endl;
cout << "Row: " << squares[loopVar]->Row << endl;
cout << "Col: " << squares[loopVar]->Col << endl;
cout << "State: " << squares[loopVar]->State << endl;
}
} //end vectorDisplay
And found that the vector displays correctly when doing the following in the driver:
Maze myMazeObject(// parameters);
myMazeObject.vectorDisplay();
and will produce output with no complaints.
But now if I try to use code like this when passing by value:
Maze myMazeObject(// parameters);
MazeSolver myMazeSolver;
myMazeSolver.someMazeSolverMethod(myMazeObject);
where someMazeSolverMethod has the line myMazeObject.vectorDisplay();I get an assertion error just as the final element in the vector is being printed.
I want to say this is my fault and my copy constructor is a p.o.s. If any insight, please let me know how to fix it and what I can do in the future!
Thanks for taking the time to read and even more so to answer should you choose to!
-J
This is your problem.
squares.push_back(myMaze.squares[loopVar]);
Basically each Maze has a vector full of the same pointers. When one copy of the maze goes out of scope it will delete all the pointers. Thus the other Maze now has a set of invalid pointers.
Couple of solutions.
Don't use pointers.
Unless you SquareData is polymorphic there seems no reason to keep pointers.
std::vector<SquareData> squares;
If you want each copy of the maze to refer to the same squares.
Then use a shared pointer. This will keep a count of the number of references to each SquareData and thus only delete them when they truly go out of scope.
std::vector<std::shared_ptr<SquareData>> squares;
Least attractive (and probably not needed).
Change the code to actually copy the pointer content into a new object.
squares.push_back(new SquareData(myMaze.squares[loopVar]));
Use of
squares.push_back(myMaze.squares[loopVar]);
in the copy constructor will lead to problems downstream.That will be vaild had the contents of squares been objects not pointers.
There are now two objects holding on to the pointers. Both willl try to call delete on the same pointer, which easily leads to undefined behavior.
You can fix the problem by:
Using a vector objects instead of a vector of pointers, or
Creating new objects from the heap and adding them to the new object.
squares.push_back(new SquareData(*myMaze.squares[loopVar]));

Pointer of class local variable? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Can a local variable's memory be accessed outside its scope?
Is there worrying thing to do a code such (getIDs() returns a pointer):
class Worker{
private:
int workerID;
int departID;
int supervisorID;
public:
Worker()
{
workerID=0;
departID=0;
supervisorID=0;
name="anonymous";
workerAddress="none";
}
void setIDs(int worker, int depart, int supervisor)
{
workerID=worker;
departID=depart;
supervisorID=supervisor;
}
int* getIDs()
{
int id[3];
id[0]=workerID;
id[1]=departID;
id[2]=supervisorID;
return id;
}
};
And then, use it such:
Worker obj;
obj.setIDs(11,22,33);
cout<<(*obj.getIDs())<<endl;
cout<<++(*obj.getIDs())<<endl;
cout<<++(++(*obj.getIDs()))<<endl;
I am wondering about that because the compiler shows:
Warning 1 warning C4172: returning address of local variable or
temporary
Your int id[3] is allocated on a stack and gets destroyed when your int* getIDs() returns.
You're return a pointer to a variable that gets destroyed immediately after getIDs() returns. The pointer then becomes dangling and is practically useless as doing anyting with it is undefined behaviour.
Suppose you defined your class like this:
class Worker{
private:
int IDs[3];
public
// ...
int* getIDs() { return IDs; }
};
This partially solves your problem, as the pointer remains valid as long the Worker object is in scope, but it's still bad practice. Example:
int* ptr;
while (true) {
Worker obj;
obj.setIDs(11,22,33);
ptr = obj.getIDs();
cout << *ptr; // ok, obj is still alive.
break;
} // obj gets destroyed here
cout << *ptr; // NOT ok, dereferencing a dangling pointer
A better way of solving this is to implement your custom operator << for your class. Something like this:
class Worker {
private:
int workerID;
int departID;
int supervisorID;
public:
// ...
friend ostream& operator<<(ostream& out, Worker w);
};
ostream& operator<<(ostream& out, const Worker& w)
{
out << w.workerID << "\n" << w.departID << "\n" << w.supervisorID;
return out;
}
Even if this would work, it wouldn't be good practice to do it this way in c++ unless there is some profound reason why you want pointers to int. Raw c-syle arrays are more difficult to handle than, for instance, std::vectors, so use those, like
std::vector<int> getIDs(){
std::vector<int> id(3);
id[0]=workerID; id[1]=departID; id[2]=supervisorID;
return id;
}
If you're worried about the overhead: this is likely to be optimized away completely by modern compilers.
A local (also caled automatic) variable is destroyed once you leave the function where it is defined. So your pointer will point to this destroyed location, and of course referencing such a location outside the function is incorect and will cause undefined behaviour.
The basic problem here is that when you enter a function call, you get a new frame on your stack (where all your local variables will be kept). Anything that is not dynamically allocated (using new/malloc) in your function will exist in that stack frame, and it gets destroyed when your function returns.
Your function returns a pointer to the start of your 3-element-array which you declared in that stack frame that will go away. So, this is undefined behavior.
While you may get "lucky/unlucky" and still have your data around where the pointer points when you use it, you may also have the opposite happen with this code. Since the space is given up when the stack frame is destroyed, it can be reused - so another part of your code could likely use the memory location where your three elements in that array is stored, which would mean they would have completely different values by the time you dereferenced that pointer.
If you're lucky, your program would just seg-fault/crash so you knew you made a mistake.
Redesign your function to return a structure of 3 ints, a vector, or at the very least (and I don't recommend this), dynamically allocate the array contents with new so it persists after the function call (but you better delete it later or the gremlins will come and get you...).
Edit: My apologies, I completely misread the question. Shouldn't be answering StackOverflow before my coffee.
When you want to return an array, or a pointer rather, there are two routes.
One route: new
int* n = new int[3];
n[0] = 0;
// etc..
return n;
Since n is now a heap object, it is up to YOU to delete it later, if you don't delete it, eventually it will cause memory leaks.
Now, route two is a somewhat easier method I find, but it's kind of riskier. It is where you pass an array in and copy the values in.
void copyIDs(int arr[3] /* or int* arr */)
{
arr[0] = workerID;
/* etc */
}
Now your array is populated, and there was no heap allocation, so no problem.
Edit: Returning a local variable as an address is bad. Why?
Given the function:
int* foo() {
int x = 5;
return &x; // Returns the address (in memory) of x
} // At this point, however, x is popped off the stack, so its address is undefined
// (Garbage)
// So here's our code calling it
int *x = foo(); // points to the garbage memory, might still contain the values we need
// But what if I go ahead and do this?
int bar[100]; // Pushed onto the stack
bool flag = true; // Pushed onto the stack
std::cout << *x << '\n'; // Is this guaranteed to be the value we expect?
Overall, it is too risky. Don't do it.

C++ basics, vectors, destructors

I'm a little confused about the best practice for how to do this. Say I have a class that for example allocs some memory. I want it to self destruct like an auto but also put it in a vector for some reason unknown.
#include <iostream>
#include <vector>
class Test {
public:
Test();
Test(int a);
virtual ~Test();
int counter;
Test * otherTest;
};
volatile int count = 0;
Test::Test(int a) {
count++;
counter = count;
std::cout << counter << "Got constructed!\n";
otherTest = new Test();
otherTest->counter = 999;
}
Test::Test() {
count++;
counter = count;
std::cout << counter << "Alloced got constructed!\n";
otherTest = NULL;
}
Test::~Test() {
if(otherTest != 0){
std::cout << otherTest->counter << " 1Got destructed" << counter << "\n";
otherTest->counter = 888;
std::cout << otherTest->counter << " 2Got destructed" << counter << "\n";
}
}
int vectorTest(){
Test a(5);
std::vector<Test> vecTest;
vecTest.push_back(a);
return 1;
}
int main(){
std::cout << "HELLO WORLD\n";
vectorTest();
std::cout << "Prog finished\n";
}
In this case my destructor gets called twice all from counter 1, the alloc' object has already been set to 888 (or in a real case freed leading to bad access to a deleted object). What's the correct case for putting a local variable into a vector, is this some kind of design that would never happen sensibly. The following behaves differently and the destructor is called just once (which makes sense given its an alloc).
int vectorTest(){
//Test a(5);
std::vector<Test> vecTest;
vecTest.push_back(*(new Test(5)));
return 1;
}
How can I make the local variable behave the same leading to just one call to the destructor? Would a local simply never be put in a vector? But aren't vectors preferred over arrays, what if there are a load of local objects I want to initialize separately and place into the vector and pass this to another function without using free/heap memory? I think I'm missing something crucial here. Is this a case for some kind of smart pointer that transfers ownership?
A vector maintains its own storage and copies values into it. Since you did not implement a copy constructor, the default one is used, which just copies the value of the pointer. This pointer is thus deleted twice, once by the local variable destructor and once by the vector. Don't forget the rule of three. You either need to implement the copy and assignment operators, or just use a class that already does this, such as shared_ptr.
Note that this line causes a memory leak, since the object you allocated with new is never deleted:
vecTest.push_back(*(new Test(5)));
In addition to what Dark Falcon wrote: To avoid reallocating when inserting into a vector, you typically implement a swap function to swap local element with a default-constructed one in the vector. The swap would just exchange ownership of the pointer and all will be well. The new c++0x also has move-semantics via rvalue-references to help with this problem.
More than likely, you'd be better off having your vector hold pointers to Test objects instead of Test objects themselves. This is especially true for objects (like this test object) that allocate memory on the heap. If you end up using any algorithm (e.g. std::sort) on the vector, the algorithm will be constantly allocating and deallocating memory (which will slow it down substantially).