How to delete the array of dynamic objects created in this following snippet?
I tried to go through some previous answers in the forum, but none could point answer for me.
#include <iostream>
struct Card{int x;};
int main()
{
std::vector<Card*> S;
for (int i = 0; i < 3; i++)
{
Card* o = new Card;
o->x = i;
S.push_back(o);
}
for (auto a : S)
std::cout << "Opening from the container " << a->x << '\n';
//delete o; --------> How to delete the array of objects???
return 0;
}
By looping through the vector and calling delete:
for(auto& elem : S)
{
delete elem;
}
Also, It's a good habit to range-loop over a container using (const) auto& instead of auto to prevent copies.
Also also, since you're using range-based for loops that means you have access to smart pointers so in reality you shouldn't be calling delete at all nor storing raw pointers.
Either store actual objects in the vector or store smart pointers like std::unique_ptr.
Related
I have java/python experience and recently started working on a C++ project. I ran into this very generic problem and wasn't able to find any clear answer/explanation in StackOverflow. The concepts behind is probably very basic, but still most of the things I tried seems to fail this far, so I thought it is worth to post it here and learn the "proper C++ way".
I'm trying to create a vector of objects in a for loop. The code I have is something like below which works:
int NUMBER_OF_OBJECTS = 6;
std::vector<SomeObject> objects = std::vector<SomeObject>(NUMBER_OF_OBJECTS);
for (int i = 0; i < NUMBER_OF_OBJECTS; i++) {
std::string name = "Object" + std::to_string(i);
test::SetObject(&objects[i], name.data());
}
however if I try something like:
std::vector<SomeObject> objects;
for (int i = 0; i < 6; i++) {
std::unique_ptr<SomeObject> object = std::make_unique<SomeObject>();
objects.push_back(*object.get());
std::string name = "Object" + std::to_string(i);
test::SetObject(&objects[i]);
}
it doesn't work (ie below prints the same address):
for (SomeObject o : objects) {
std::cout << "object address: " << &o << "\n";
}
I thought that's because the docs of unique_ptr says "The object is destroyed and its memory deallocated when ... unique_ptr managing the object is destroyed". So I tried to preserve the unique_ptr by creating a vector of it, something like:
std::vector<std::unique_ptr<SomeObject>> objects;
for (int i = 0; i < 6; i++) {
std::unique_ptr<SomeObject> object = std::make_unique<SomeObject>();
objects.push_back(object);
std::string name = "Object" + std::to_string(i);
test::SetObject(&(*objects[i].get()));
}
but instead of preserving the unique_ptr, this instead still destroys the object and warns me call to implicitly-deleted copy constructor of 'std::unique_ptr<SomeObject>'
I guess putting the unique_ptr to a vector is not enough to make C++ not destroy that unique_ptr, maybe I need to do something like std::move? I feel like something as basic as initialising a list of objects is probably done very frequently and should have a simpler way to it.
I would greatly appreciate if anyone could elaborate how memory management works in C++ for practical purposes (eg. I know I could use new, but read that in most cases I should use make_unique instead to avoid leaking memory)
It's not your other code that is flawed, it's the loop where you print the addresses to the objects:
for (SomeObject o : objects) {
std::cout << "object address: " << &o << "\n";
}
Here a brand new o object will be created each iteration of the loop. But nothing stops the compiler to reuse the same memory for the object o.
If you want to get each "unique" object from the container, use references instead:
for (SomeObject const& o : objects) { ... }
std::unique_ptr<SomeObject> object = std::make_unique<SomeObject>();
objects.push_back(*object.get());
can be simplified to
SomeObject object{};
objects.push_back(object);
or even
objects.emplace_back();
Your issue in 2nd/3rd snippet is that vector is resized, so inernal pointer and iterator are invalidated:
test::SetObject(&objects[i]); // dangling pointer after objects.push_back(*object.get());
std::vector::reserve might solve your issue:
std::vector<SomeObject> objects;
object.reserve(6);
for (int i = 0; i < 6; i++) {
SomeObject object{};
objects.push_back(object);
std::string name = "Object" + std::to_string(i);
test::SetObject(&objects[i]);
}
or use vector of (smart) pointer:
std::vector<std::unique_ptr<SomeObject>> objects;
// object.reserve(6); // No longer needed
for (int i = 0; i < 6; i++) {
std::unique_ptr<SomeObject> object = std::make_unique<SomeObject>();
objects.push_back(std::move(object));
// or simply
// objects.push_back(std::make_unique<SomeObject>());
std::string name = "Object" + std::to_string(i);
test::SetObject(objects[i].get());
}
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.
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
I'm writing a game framework, I have a vector<unique_ptr<Object>> list and I distribute pointers from that list by calling object.get() and sending that out. Before that I send out references instead of raw pointers but that resulted in other weird problem so I was told this is better. However when I remove a unique_ptr<Object>from the list, the raw pointers remains. I also can't deallocate them manually, I get an exception saying the pointer is not allocated.
So my question would be:
How do I delete raw pointers from removed unique_ptr's?
and is also a more general question:
Am I on the right track structure wise of passing pointers instead of references?
PxlObject* PxlFramework::AddObject(PxlObject* obj)
{
std::unique_ptr<PxlObject> u_ptr(obj);
objects_iterator = objects.insert(objects.end(), std::move(u_ptr));
return obj;
}
void PxlFramework::DeleteObject(PxlObject* obj) {
for(objects_iterator = objects.begin(); objects_iterator != objects.end(); ++objects_iterator)
{
if((*objects_iterator)->get_id() == obj->get_id())
{
//attempting to delete the raw pointer here but it will result in an error
delete obj;
//removing the unique_ptr<PxlObject> from the list here
std::swap((*objects_iterator), objects.back());
objects.pop_back();
break;
}
}
}
The whole point of std::unique_ptr is that it "owns" the object and it manages deletion automatically when the unique_ptr is destroyed. As such, you should not delete either a unique_ptr nor anything that a unique_ptr owns. To avoid this confusion, references are more common. Additionally, you have the oddity that your AddObject returns a pointer to a PxlObject that is not the one just added.
Something like this might be a little cleaner:
template<class Us...>
PxlObject& PxlFramework::AddObject(Us&&... obj)
{
std::unique_ptr<PxlObject> u_ptr(new PxlObject(std::forward<Us>(obj)...));
objects_iterator = objects.insert(objects.end(), std::move(u_ptr));
return **objects_iterator;
}
void PxlFramework::DeleteObject(PxlObject& obj) {
auto finder = [](std::unique_ptr<PxlObject>& p)->bool
{return obj.get_id()==p->get_id();};
auto it = find_if(objects.begin(), objects,end(), finder);
if (it != objects.end())
objects.erase(it);
else
throw ...;
}
You don't need delete the raw pointer directly you can use vector.erase instead. Here you have a simple example:
#include <iostream>
#include <algorithm>
#include <memory>
#include <vector>
using namespace std;
typedef vector<unique_ptr<int>> ptr_list_t;
void remove_number(int x, ptr_list_t& ptr_list)
{
for (ptr_list_t::iterator it = ptr_list.begin(); it != ptr_list.end(); ++it)
if (*(it->get()) == x) {
ptr_list.erase(it); // Use vector.erase for deleting objects from a vector.
// since it points to a unique_ptr, the object owned by it
// will be destroyed automatically.
break;
}
}
int main()
{
ptr_list_t ptr_list;
// Generating the pointer to numbers. 0 - 9
for (int i = 0; i < 10; i++)
ptr_list.push_back(unique_ptr<int>(new int(i)));
// Remove the number 3.
remove_number(3, ptr_list);
// Printing the list. The number 3 will not appear.
for (ptr_list_t::iterator it = ptr_list.begin(); it != ptr_list.end(); ++it)
cout << *(it->get()) << endl;
return 0;
}
Other thing, I'm agreed with #MooingDuck: you should not delete either a unique_ptr nor anything that a unique_ptr owns. But you sure can. Take a look on unique_ptr.release. This function frees the ownership of the managed object.
If I have a list<object*>>* queue and want to pop the first object in the list and hand it over to another part of the program, is it correct to use (sketchy code):
object* objPtr = queue->first();
queue->pop_first();
return objPtr; // is this a pointer to a valid memory address now?
?
According to the documentation on http://www.cplusplus.com/reference/stl/list/pop_front/ it calls the destructor of the deleted element, but I'm confused as to whether it means the linked list's node object, or the actually stored "user" object.
Edit: I might be front instead of first, my bad.
Yes, it is a valid pointer. List will not release the memory allocated by you. List will destroy its internal not the user object.
Yes it's valid: Since you put pointers into the list, only the pointer gets destroyed, not the object itself.
Yes objPtr contains pointer to a valid memory.
When you insert an element into a std::list, list makes a copy of it. In your case the element is an address (a pointer) so list makes a copy of the address and stores it.
object * optr = queue->pop_front();
optr now points to the object
queue->pop_front();
removes the element (an address/pointer) from the list, optr already points to your object.
After you're done with the object don't forget do delete it otherwise you end up with memory leak.
Example:
#include <iostream>
#include <list>
using namespace std;
struct A
{
static int count;
A() : val(count++) { cout << "A(" << val << ")" << endl; }
~A() { cout << "~A(" << val << ")" << endl; }
int val;
};
int A::count = 0;
ostream& operator<<(ostream& os, A& a) { return os << a.val; }
int main()
{
list<A*> alist;
for (unsigned int i = 3; i; --i) alist.push_back(new A());
for (unsigned int i = 3; i; --i)
{
A * aptr = alist.front();
alist.pop_front();
cout << *aptr << endl;
delete aptr;
aptr = 0;
}
}
The standard indeed says (23.2.2.3/5) that the destructor of the element's type is called. But this type is a pointer here, and the destructor of a pointer does nothing...
Your code is well but it is better to use list< boost::shared_ptr<object> >.
shared_ptr < object> objPtr = queue->first();
queue->pop_first();
return objPtr;
When you remove the elements, STL containers will not destroy the user objects allocated on heap.
class A
{
};
list<A*> PointerToObjectList;
A* ptr = new A();
PointerToObjectList.push_back(ptr);
If you remove the ptr from the list, list will not delete the object automatically. You need to explicitly call delete once the object is no longer being used.