inconsistent object IDs inside multiple vector in C++ - c++

just a beginner here.
i'm trying to store some objects inside a vector, so i can loop it later, but the reference changes afterwards, i'm not sure what happened
the code's below;
#include <iostream>
#include <vector>
using namespace std;
class Car;
class Garage {
public:
vector<Car*> vCar;
};
class Car {
public:
short id;
};
int main()
{
Garage garage;
short i;
for(i = 0; i < 10; i++) {
Car car;
car.id = i;
garage.vCar.push_back(&car);
}
for(i = 0; i < garage.vCar.size(); i++) {
cout << i << " " << garage.vCar[i]->id << endl;
// output 9,9,9,..9 instead of 1,2,3,4...10, why is that?
}
return 0;
}

vector<Car*> vCar;
is a vector that stores pointers to Car objects.
for(i = 0; i < 10; i++) {
Car car;
car.id = i;
garage.vCar.push_back(&car);
}
Inside the above for loop, you create Car objects on stack. By the end of the for loop, those objects are out of scope and will be destroyed. Therefore, your pointers inside the vector point to some objects that do not exist. You have undefined behavior in your code.
You may store objects directly, which stores copy of the original objects. You can find a Live Demo here.

You're pushing the address of a stack-based object into the vector, but that stack based object will be destroyed as soon as it goes out of scope (so as soon as the iteration of the for-loop is complete). When you dereference the pointer later on you're actually reading from the address on the stack where the last object was created, which is why you get the same value every time.
How you fix this is up to you - you could change the vector to store Car objects rather than pointers to Car objects, you could use smart pointers, etc..

Change
class Garage {
public:
vector<Car*> vCar;
};
To
class Garage {
public:
vector<Car> vCar;
};
And
garage.vCar.push_back(&car);
To
garage.vCar.push_back(car);
This will eliminate the undefined behaviour that you are experiencing ( you are taking an address of an item off the stack!)

Related

Deleting dynamic elements in a vector

I have a program that has a vector. The vector takes pointers to an object which I dynamically create in my program. I then wish to delete these dynamic objects from the vector. For example:
int main()
{
vector<Account*> allAccounts;
auto timeDone = chrono::system_clock::now();
time_t transactionTime = chrono::system_clock::to_time_t(timeDone);
Account* a1 = new Savings(0, "Savings");
Account* a2 = new Current(0, "Current");
allAccounts.push_back(a1);
allAccounts.push_back(a2);
Transaction* initialTransaction = new Transaction("Initial Deposit", transactionTime, balanceAnswer);
allAccounts[0]->addTransaction(initialTransaction);
allAccounts[1]->addTransaction(initialTransaction);
for (int i = 0; i < allAccounts.size(); i++)
{
delete allAccounts[i]; //deletes all dynamically created accounts
}
}
I believed this was fine to do, however I'm starting to wonder if this does correctly delete the pointers in the vector. However I used a cout << allAccounts.size() after the delete and it still gives the size as 2 as if the account pointers were still in the vector.
Is this meant to happen?
Another note is that the Account object also has a vector of dynamic pointers that get passed from main in a function (allAccounts[i]->addObject(object)) and then these objects get deleted in a destructor in the same way. Is this also a valid thing to do?
Just so I get my worries out the way, this is what I do in account:
float balance;
string accountType
private vector <Transaction*> history;
Account::Account(float b, string a)
{
balance = b;
accountType = a;
}
void Account::addTransaction(Transaction* t)
{
history.push_back(t);
}
Account::~Account()
{
for (int i = 0; i < history.size(); i++)
{
delete history[i];
}
history.clear();
}
What you are doing is fine (assuming Account has a virtual destructor) and there is no memory leak. The size of the vector is not affected by deleting the pointers you store in it.
The destructor needs to be virtual to not cause your program to have undefined behavior.
I would recommend storing a smart pointer like std::unique_ptr<Account> in the vector instead though. That would make the destruction of the stored objects automatic when the vector.is destroyed.

I get an error when trying to make a vector of classes inside of the same class

I am trying to make a class with decendants of the same class, to make a tree, but when i try to access something insode of the vector it never works. i get an exception: std::length_error when trying to access the string.
#include <iostream>
#include <vector>
#include <string>
using namespace std;
class A {
public:
string name;
vector<A*> children;
};
int main()
{
A cl;
cl.name= "HI!";
for(int i = 0; i < 10;i++) {
A newCl;
newCl.name= "World!";
cl.children.push_back(&newCl);
}
for(int i = 0; i < 10;i++) {
// error here:
cout << cl.children[i]->name << endl;
}
return 0;
}
Anybody know an easier way to make a tree in C++, or how to fix this?
The problem is in this loop
for(int i = 0; i < 10;i++) {
A newCl;
newCl.name= "World!";
cl.children.push_back(&newCl);
}
The variable newCl will cease to exist at the end of the iteration and you are inserting its address in the vector. When you access it, you are accessing a dangling pointer, this is undefined behavior and your program can crash, produce garbage or anything in between.
You can use heap allocation as proposed by Oblivion, but in such a case you might want to consider the use of smart pointers for memory management.
Otherwise, you can have a vector of values std::vector<A> instead of pointers, possible from C++17 (for more details, see: How can I declare a member vector of the same class?)
Edit: I clarified the use of std::vector<A> after Chipster's comment.
You store reference to a temporary as children:
A newCl;
newCl.name= "World!";
cl.children.push_back(&newCl);
Once you are out of scope the children will dangle.
A* newCl = new A;
Should fix. But you have to go through the vector to free your children.
If you had a reason to use pointers, it is better to use smart pointers:
vector<shared_ptr<A>> children;
Live

Pointer Copy to Out of Scope c++

Today i went back and investigated an error i got in an old project. It's not exactly an error, rather, i don't know how to do what i need to do. Don't really want to go into the details of the project as it is old and buggy and inefficient and more importantly irrelevant. So i coded a new sample code:
#include <iostream>
#include <vector>
#include <time.h>
#include <random>
#include <string>
class myDoc;
class myElement
{
int myInt;
std::string myString;
myElement * nextElement;
//a pointer to the element that comes immediately after this one
public:
myElement(int x, std::string y) : myInt(x), myString(y){};
friend myDoc;
};//an element type
class myDoc
{
std::vector<myElement> elements;
public:
void load();
~myDoc()
{
//I believe i should delete the dynamic objects here.
}
};// a document class that has bunch of myElement class type objects as members
void myDoc::load()
{
srand(time(0));
myElement * curElement;
for (int i = 0; i < 20; i++)
{
int randInt = rand() % 100;
std::string textInt = std::to_string(randInt);
curElement = new myElement(randInt,textInt);
//create a new element with a random int and its string form
if (i!=0)
{
elements[i-1].nextElement = curElement;
//assign the pointer to the new element to nextElement for the previous element
//!!!!!!!!!!!! this is the part that where i try to create a copy of the pointer
//that goes out of scope, but they get destroyed as soon as the stack goes out of scope
}
elements.push_back(*curElement);// this works completely fine
}
}
int main()
{
myDoc newDoc;
newDoc.load();
// here in newDoc, non of the elements will have a valid pointer as their nextElement
return 0;
}
Basic rundown: we have a document type that consists of a vector of element type we define. And in this example we load 20 random dynamically allocated new elements to the document.
My questions/problems:
When the void myElement::load() function ends, the pointer and/or the copies of it goes out of scope and get deleted. How do i keep a copy that stays(not quite static, is it?) at least until the object it points to is deleted?
The objects in the elements vector, are they the original dynamically allocated objects or are they just a copy?
I allocate memory with new, how/when should i delete them?
Here is a picture i painted to explain 1st problem(not very accurate for the specific example but the problem is the same), and thank you for your time.
Note: I assumed you want a vector of myElement objects where each one points to the element next to it. It is unclear if you want the objects in elements to point to copies of them, anyway it should be pretty easy to modify the code to achieve the latter
This is what happens in your code:
void myDoc::load()
{
..
curElement = new myElement(n,m); // Create a new element on the heap
...
// If this is not the first element we inserted, have the pointer for the
// previous element point to the heap element
elements[i-1].nextElement = curElement;
// Insert a COPY of the heap element (not the one you stored the pointer to)
// into the vector (those are new heap elements copied from curElement)
elements.push_back(*curElement);// this works completely fine
}
so nothing gets deleted when myDoc::load() goes out of scope, but you have memory leaks and errors since the pointers aren't pointing to the elements in the elements vector but in the first heap elements you allocated.
That also answers your second question: they're copies.
In order to free your memory automatically, have no leaks and point to the right elements you might do something like
class myElement
{
int a;
std::string b;
myElement *nextElement = nullptr;
//a pointer to the element that comes immediately after this one
public:
myElement(int x, std::string y) : a(x), b(y){};
friend myDoc;
};//an element type
class myDoc
{
std::vector<std::unique_ptr<myElement>> elements;
public:
void load();
~myDoc()
{}
};// a document class that has bunch of myElement class type objects as members
void myDoc::load()
{
srand((unsigned int)time(0));
for (int i = 0; i < 20; i++)
{
int n = rand() % 100;
std::string m = std::to_string(n);
//create a new element with a random int and its string form
elements.emplace_back(std::make_unique<myElement>(n, m));
if (i != 0)
{
//assign the pointer to the new element to nextElement for the previous element
elements[i - 1]->nextElement = elements[i].get();
}
}
}
Live Example
No need to delete anything in the destructor since the smart pointers will be automatically destroyed (and memory freed) when the myDoc element gets out of scope. I believe this might be what you wanted to do since the elements are owned by the myDoc class anyway.

why is the dynamically allocated object going out of scope outside the function?

I want to allocate objects on the heap according to a string entered by the user but I cannot access the pointers or objects outside the function although they are on the heap. As well, I tried to allocate them using unique pointers but I'm still getting an error saying "not declared" etc.
How can I create these objects, a user can create eight objects concurrently with spaces between the words. (e.g. "Avalanche Toolbox Paperdoll" and so on)?
string user_input;
getline(cin, user_input);
istringstream iss(user_input);
copy(istream_iterator<string>(iss),
istream_iterator<string>(),
back_inserter(vec));
for(int i=0; i<8; i++)
{
if(vec.at(i)=="Avalanche")
{
Avalanche *avalanche = new Avalanche(5);
std::unique_ptr<Avalanche> ptr(new Avalanche(5)); // even tried using unique pointer.
cout<<"Avalanche: "<<avalanche->c_game<<endl;
}
else if(vec.at(i)=="Bureaucrat")
{
Bureaucrat *bureaucrat = new Bureaucrat(5);
cout<<"Bureaucrat: "<<bureaucrat->c_game<<endl;
}
else if(vec.at(i)=="Toolbox")
{
Toolbox *toolbox = new Toolbox(5);
cout<<"Toolbox: "<<toolbox->c_game<<endl;
}
else if(vec.at(i)=="Crescendo")
{
Crescendo *crescendo = new Crescendo(5);
cout<<"Crescendo: "<<crescendo->c_game<<endl;
}
else if(vec.at(i)=="Paperdoll")
{
Paperdoll *paperdoll = new Paperdoll(5);
cout<<"Paperdoll: "<<paperdoll->c_game<<endl;
}
else if(vec.at(i)=="FistfullODollars")
{
Fistfullodollars *fistfullodollars = new Fistfullodollars(5);
cout<<"FistfullOdollars: "<<fistfullodollars->c_game<<endl;
}
}
cout<<ptr.c_game<<endl; // give an error not declared
Your object lifetime is limited to it's scope. In your case, the scope is within two closest {}. You need to remember that when you have a (smart)pointer to allocated memory, you actually have TWO objects - one is your (smart) pointer, and the other is the object the pointer points to. When the pointer goes out of scope, you can not reference the actual object by this pointer anymore. And if there is no other pointer pointing to this object, the object is lost forever, and you have is a classic example of so called memory leak - there is an object somewhere there, but is unaccessible, and the memory occupied by it is lost and can not be reused.
Think about it in a following way - you have a book and a library card. The book is somewhere in the vast storage, and unless you know where to look (using library card) you will never find it. So if you lost all copies of your library cards, the book is as good as lost to you - though it is obviously somewhere there.
The answer is, that your objects created are not deleted, since you have created them on the heap, as you pointed out, but the pointer variables go out of scope. The solution is, to put the declaration outside of the scopes and do the assignment in the scope:
string user_input;
getline(cin, user_input);
istringstream iss(user_input);
copy(istream_iterator<string>(iss),
istream_iterator<string>(),
back_inserter(vec));
Bureaucrat *bureaucrat;
Toolbox *toolbox;
Crescendo *crescendo;
Paperdoll *paperdoll;
Fistfullodollars *fistfullodollars;
for(int i=0; i<8; i++)
{
if(vec.at(i)=="Avalanche")
{
Avalanche *avalanche = new Avalanche(5);
std::unique_ptr<Avalanche> ptr(new Avalanche(5)); // even tried using unique pointer.
cout<<"Avalanche: "<<avalanche->c_game<<endl;
}
else if(vec.at(i)=="Bureaucrat")
{
bureaucrat = new Bureaucrat(5);
cout<<"Bureaucrat: "<<bureaucrat->c_game<<endl;
}
else if(vec.at(i)=="Toolbox")
{
toolbox = new Toolbox(5);
cout<<"Toolbox: "<<toolbox->c_game<<endl;
}
else if(vec.at(i)=="Crescendo")
{
crescendo = new Crescendo(5);
cout<<"Crescendo: "<<crescendo->c_game<<endl;
}
else if(vec.at(i)=="Paperdoll")
{
paperdoll = new Paperdoll(5);
cout<<"Paperdoll: "<<paperdoll->c_game<<endl;
}
else if(vec.at(i)=="FistfullODollars")
{
fistfullodollars = new Fistfullodollars(5);
cout<<"FistfullOdollars: "<<fistfullodollars->c_game<<endl;
}
}
cout<<ptr.c_game<<endl; // give an error not declared
ptr is declared on the stack, it's the object it's pointing at which is delete bound.
when if(vec.at(i)=="Avalanche") {} is over, ptr (which is stack allocated) gets out of scope and no longer accesible.
Even if you allocate your object dynamically you still need a pointer variable to keep track of where that memory is. Your ptr variable is destroyed at the end of the enclosing braces.
I'm guessing all your classes Avalanche, Bureaucrat... inherit from some base class with a c_game member variable. Perhaps something a bit like this:
struct MyBase {
virtual ~MyBase(){} // This is important!
MyBase(std::string c_game) : c_game(c_game) {}
std::string c_game;
};
struct Avalanche : public MyBase {
Avalanche(int num) : MyBase("Avalanche"), num(num) {}
int num;
};
struct Fistfullodollars : public MyBase {
Fistfullodollars(int num) : MyBase("Fistfullodollars"), num(num) {}
int num;
};
//...
In order to keep track of these dynamically allocated objects you could construct a container of (smart) pointers to this base class:
std::vector<std::unique_ptr<MyBase>> objects;
for(size_t i=0; i!=vec.size(); i++)
{
if(vec.at(i)=="Avalanche")
{
objects.push_back(std::make_unique<Avalanche>(5));
std::cout<<"Avalanche: "<<objects.back()->c_game<<"\n";
}
else if(vec.at(i)=="FistfullODollars")
{
objects.push_back(std::make_unique<Fistfullodollars>(5));
std::cout<<"FistfullOdollars: "<<objects.back()->c_game<<"\n";
}
//...
}
for (const auto& ptr : objects)
{
std::cout << ptr->c_game << "\n";
}
Live demo.

Array of pointers to nodes not declared in scope

I'm trying to assign a node to a pointer along an array of pointers but it keeps telling me that my array was not declared in the scope. I'm totally confused on how or why so any help would be greatly beneficial! Thanks for taking the time to respond!
#include <iostream>
#include "book.h"
using namespace std;
class bookstore
{
private:
int amount = 5;
int counting = 0;
public:
bookstore()
{
bookstore *store;
store = new book*[amount];
for(int i = 0; i < amount; i++)
{
store[i] = NULL;
}
}
~bookstore(){ delete[] store; }
void addbook(string a,string b, string c, string d, string e)
{
if (counting == amount)
{
cout<<"Full House!"<<endl;
return;
}
store[counting] = new book(a,b,c,d,e);
counting++;
}
void print()
{
for(int i = 0; i < amount; i++)
{
cout<<store[i]->name<<" "<<store[i]->publisher<<" "<<store[i]->year<<" "<<store[i]->price<<" "<<store[i]->category<<endl;
}
}
};
Your pointer store is local to the default constructor. It looks like you're after a data member. Furthermore, you seem to be after an array of pointers. If so, you need bookstore needs to be a pointer to pointer:
class bookstore
{
private:
bookstore** store; // or bookstore* store
int amount = 5;
int counting = 0;
and fix the constructor to use that:
bookstore()
{
store = new book*[amount]; // or store = new book[amount]
....
Note that your class is attempting to manage dynamically allocated resources, so you will need to take care of the copy constructor and assignment operators (either make the class non-copyable and non-assignable, or implement them. The defaults are not acceptable. See the rule of three.) If you are really using an array of dynamically allocated pointers, then you need to fix your destructor too. Currently, it only deletes the array, but not the objects pointed at by the pointers in it.
The better solution would be to use a class that manages the resources for you and has the desired semantics. It is easier to have each class handle a single responsibility.