Vector of object pointers and objects going out of scope - c++

I am using a derived class and a vector of pointers to objects from said class. I'm having some problems implementing copy constructors etc, even after reading a lot about it. I'm using c++11.
I have a loop where new objects of the derived class are created, and I then want to put these into the vector. But since it is a vector of pointers I must put the address of the created object there instead.
I believe my problems stem from this fact, together with objects going out of scope etc and my not being able to implement copy constructors / copy assignment constructors etc in a satisfactory way.
I've made a minimal example that I think illustrates my problem. Let's say the initial setup is as follows (I know it doesn't make much sense, e.g. with the pointer *n, but I think this shows the issues with my actual code):
using namespace std;
#include <iostream>
#include <vector>
class Base {
protected:
int* n;
public:
void display(string name="") {cout << name << "n = " << *n << endl;}
Base() {}
Base(int n_) {
*n=n_;
cout << "Initialised to " << *n << endl;
}
};
class Derived : public Base {
public:
Derived() : Base() {}
Derived(int n_) : Base(n_) {}
};
int main(int argc, const char* argv[]) {
vector<Base*> list;
for(int i=0;i<5;i++) {
Derived tmp(i);
tmp.display("Tmp: ");
list.push_back(&tmp);
}
cout << endl;
for(int i=0;i<list.size();i++) {
cout << "Address of " << i << ": " << list[i] << endl;
list[i]->display("Element "+to_string(i)+" : ");
}
}
The output of this is:
Initialised to 0
Tmp: n = 0
Initialised to 1
Tmp: n = 1
Initialised to 2
Tmp: n = 2
Initialised to 3
Tmp: n = 3
Initialised to 4
Tmp: n = 4
Address of 0: 0x7fff3a1df2d0
Element 0 : n = 0
Address of 1: 0x7fff3a1df2d0
Element 1 : n = 0
Address of 2: 0x7fff3a1df2d0
Element 2 : n = 0
Address of 3: 0x7fff3a1df2d0
Element 3 : n = 0
Address of 4: 0x7fff3a1df2d0
Element 4 : n = 0
So after the loop all the elements in the list point to the same address, where n=0 (probably undefined behaviour from tmp going out of scope).
So rather than just putting the address of tmp into list I'm thinking I somehow have to make instances of Derived that survive the loop while still just having addresses in list.
As mentioned I've tried doing this using various special member functions with no luck.
Note that it might seem implementing a vector of the objects themselves might be easier, but that leads to other problems in my actual code. If I can't get this working I'll try that instead though.

It has nothing to do with with copying or copy-constructors, it is simply only because the objects go out of scope and gets destructed, while you still keep a pointer to these (now destructed) objects. This leads to undefined behavior when you try to dereference these pointers.
Instead you need to dynamically allocate these objects, using e.g. new. You could wrap these pointers using C++11 smart pointers.

You add pointers to objects on the stack to your vector. When the current scope ends, these objects will be destroyed, but the pointer is still there.
You'll have to create new objects instead.
int main(int argc, const char* argv[]) {
vector<Base*> list;
for(int i=0;i<5;i++) {
auto tmp = new Derived{i};
tmp->display("Tmp: ");
list.push_back(tmp);
}
// ...
}
}
Now you still have to make sure, you free the objects as needed. Whenever possible prefer to resort to unique_ptr<> or shared_ptr<>:
int main(int argc, const char* argv[]) {
vector<unique_ptr<Base>> list;
for(int i=0;i<5;i++) {
auto tmp = make_unique<Derived>(i);
tmp->display("Tmp: ");
// this should move the unique_ptr and therefore transfer
// its ownership to the vector.
list.emplace_back(tmp);
}
// ...
}
}
Now the objects will be destroyed, either when they are removed from the vector, or when the vector is destroyed. With shared_ptr that might be delayed, untill no part of your programm holds any shared_ptr<> to the same object.

Related

How to observe c++ destructor destroys basic data types?

I have two classes one is main and other is Test, for the Test class, I have Test.cpp and Test.h
//-----Test.h--------//
#pragma once
class Test
{
private:
int num;
public:
Test(void);
Test(int n);
~Test(void);
};
//------Test.cpp------//
#include "Test.h"
#include<iostream>
using namespace std;
Test::Test(void)
{
}
Test::Test(int n)
{
num = n;
}
Test::~Test(void)
{
cout << "Deleted" << endl;
cout << "num = " << num << endl ;
}
//---------main.cpp--------------//
#include "Test.h"
#include<iostream>
using namespace std;
int main()
{
Test t1 = Test(5);
return 0;
}
The output which I have expected is
Deleted
num = 0
But Real Output is
Deleted
num = 5
Why this occurs, why destructor, dint free the memory
or dint delete the basic data type, How can I delete the variable,
Using what method I can observe basic datatype getting deleted?
Destruction of an object does not mean setting values to zero. That would be unnecessary work. Rather, all that is required is that resources be released. Bits are typically left as-is (representing 5 in your example) unless there is a compelling reason to do otherwise.
Furthermore, members are destroyed after the class. In your example, first ~Test() is run to destroy t1, then t1.num would be destroyed. The destructor of Test cannot view the destruction of Test::num.
why destructor, dint free the memory or dint delete the basic data type
You did not have any memory allocated in the heap, so there is no need to free anything.
All you have is a basic type int which does not need any memory deallocation.
If instead you had some pointer member variable:
private:
int* num;
and you allocated it somewhere in your constructor: new int(6); then sure you must deallocate/free it inside your destructor.
In this case, probably a shared-pointer may help, which automatically is destroyed just after the destructor:
std::shared_ptr<int> num;
But it has to be constructed, in the constructor you need:
Test::Test(int n)
: num(std::make_shared<int>(n)
{
// *n == 100
}
To see if the data is deleted use Valgrind.

Store array into dynamic memory

I'm passing an array to a constructor. Constructor has two parameters, pointer to int called data and int which is size of an array.
I'm allocation dynamic memory in constructor definition for this array and passing array pointer to this storage.
Last but one step is printing values in array through the pointer which is pointing to the first int value of this array.
The last step is freeing up memory in destructor delete [] data. In this step I got an error message: Debug Assertion Failed! Expression: _CrtlsValidHeapPpinter(block).
I'm very new in C++ so I'm struggling what I did wrong in below program. Could you give me a hint, please?
#include <iostream>
class Test
{
private:
int* data;
int size;
public:
// constructor and destructor
Test(int* d, int s);
~Test();
// few void methods
void display_data(int size)
{
for (int i{ 0 }; i < size; ++i)
{
std::cout << data[i] << " ";
}
std::cout << std::endl;
}
};
Test::Test(int* d, int s)
: data{nullptr}, size(s)
{
data = new int[s];
data = d;
}
Test::~Test()
{
std::cout << "Destructor is freeing memory" << std::endl;
delete[] data;
}
int main()
{
int data_array[5]{ 2,8,6,10,20 };
Test* t1 = new Test(data_array, 5);
t1->display_data(5);
delete t1;
return 0;
}
In yout Test::Test constructor you don't copy the array, you just copy the pointer. You need to use std::copy or memcpy (C-style) to copy the contents of d into data.
However, I would recommend to use STL containers (i.e., std::vector) instead of raw pointers. It will allow you to get rid of manual resource management (new/delete), which is error-prone and redundant.
You need to copy the data here. Instead of :
data = new int[s];
data = d;
Which creates an array and then forgets about it. This would lead to the array being deleted multiple times!
Copy the content of your array:
std::copy(d, d+s, data);
Or even better, use std::vector.

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

inconsistent object IDs inside multiple vector in 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!)

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).