Some simple code show first:
Type A:
//create a queue
queue<my_class*> temp;
//add some element some pointers;
temp.push(A);
temp.push(B);
...
//then i want to delete the first element ;
temp.pop();
Question 1: When call temp.pop() it will release all the object memory
A used?
If not , what i should do ?
Type B:
//create a queue
queue<my_class> temp;
//add some element some pointers;
temp.push(A);
temp.push(B);
...
//then i want to delete the first element ;
temp.pop();
Question 2: What's difference with the Type A and Type B;
Q2: pop for Type A and Type B does the same thing, the pop destructs the type that is defined in the template argument (for Type A its a pointer to my_class for Type B it is my_class). So Type A destructs a pointer Type B destructs an instance of my_class.
Q1: Yes as A is just a pointer. But it does not destruct the object A is pointing to. So the instance of my_class is not released.
pop() indeed destroys the first element.
Note however that in the first case the std::queue is of naked pointers and destroying a naked pointer doesn't do anything to the pointed-to object.
In the second case the std::queue contains object copies so when calling pop() the first copy will be destroyed and removed.
In the first case unless someone else knows the address of the object pointed to by the destroyed pointer and calls delete on that address, the object will be "leaked" (i.e. just forgotten about): its destructor will never be called and the memory it is using will never be reclaimed and reused for something else.
To destroy the pointed-to object in the first case the normal procedure is
delete queue.front();
queue.pop();
If instead of "naked" pointer you use "smart" pointers then the "leak" problem will go away in most cases(*). Note that it doesn't mean the destructor of the pointed-to object will be called in pop(), but that it will called at the appropriate time when no one else knows the address of the pointed-to object (if everything is done correctly when manipulating the smart pointers).
(*) If your data model is complex and you have std::shared_ptr networks of objects pointing to each other then there is a risk of creating "reference loops". In this case std::shared_ptr even if used correctly is not enough to prevent leaking of loops (e.g. leaking a cople of objects A and B where each one has a std::shared_ptr to the other) and a true garbage collector is needed. Unfortunately C++ doesn't provide this kind of machinery in the standard library.
Related
I am trying to find out how can I delete children of my Block class. I tried to do it with raw pointer. I don't know why, but it didn't work. I was getting the scalar deleting error. I now tried to do this with std::shared_ptr. I t didn't work as well. I am removing the children with:
void Block::remove(Block* block)
{
std::shared_ptr<Block> ptr(block);
auto it = std::find(children.begin(), children.end(), ptr);
if (it != children.end())
{
*it = NULL;
children.erase(it);
}
}
and the Block deleter is:
Block::~Block()
{
for (auto& child : this->children)
{
child = NULL;
}
if (!this->children.empty())
this->children.clear();
}
According to the debugging process, the ptr variable is found and then deleted. At the point of deleting everything works well until the last line, where I am getting the scalar deletion error. Just for the record: the children variable is of type std::vector<std::shared_ptr<Block>>.
EDIT:
The full code is here: https://github.com/DragonGamesStudios/Ages-of-Life. All the block functions are defined in AOLGuiLibrary/source/Block.cpp
You are mixing shared_ptrs with raw pointers, and that is a bad practice. If I understand correctly, you store the blocks in the vector of shared pointers, and that means that this vector has an ownership on these objects. When you create an additional shared_ptr out of a raw pointer you create another object that has the ownership on the same object:
std::shared_ptr<Block> ptr(block);
As the result, you would try to delete the object twice, and that leads to the undefined behavior.
First of all: do you need shared pointers? Consider using unique_ptr as a less error prone idea (if only one pointer object has the ownership, it is easier to understand who and when would destroy the underlying object).
Next, NEVER use raw pointers in this context: you may use raw pointers only when you don't store/delete the object. And for sure don't create smart pointers out of something that is already stored in one of them already.
Once a pointer has been given to a shared_ptr, that shared_ptr owns it. You must never again give that pointer to another shared pointer.
int * ptr = new int(1234);
{
std::shared_ptr<int> shp1(ptr); // shp1 owns ptr
std::shared_ptr<int> shp2(ptr); // shp2 owns ptr ???
}
// at this point ptr has been deleted twice
Note: it's preferable to not use new but to call std::make_shared and never give raw pointers to shared_ptr in the first place.
What you are doing to search for a child is exactly this problem. Passing in a raw pointer, you create a new owner for it. If that pointer is a child, it's already owned. You must not create shared pointers from raw pointers after they have been given to a shared pointer.
Also, the destructor you showed for Block isn't wrong, but it is completely unnecessary. All of what you coded there would happen automatically. Block is destroyed, it destroys the vector it holds (so clearing it is unnecessary.) The vector destroys its elements, so the shared pointers it holds are cleaned up too.
If block points at array code, this code is illegal, because for a new[] you have to call delete[], and std::shared_ptr<Block> would call delete. After that heap would be corrupted and further operations may fail. Same happens if blocks points to an element of array. If blocks points to object not located in heap, it also would result in error.
In general it's bad idea to delete a pointer passed to a function. There is no guarantee that the pointer was one returned by new, and even if it was: by which new?
To create a strong reference counter for an array, you have to use std::shared_ptr<Block[]>, but usually it's better idea to use some kind of container.
To find a value of pointer object in array of shared pointers:
auto it = std::find_if( children.begin(), children.end(), [=](auto& el) {
return el.get() == block;
});
If childrenis not static (that's not some kind of factory), then that destructor code is completely redundant. After call to ~Block() there will be calls to destructors of every member of Block, including that collection which would deallocate its resources and call destructor to every pointer, which would call destructor to every Block.
First time I am using smart pointers in my project. While using unique_ptr, I got some doubts regarding unique_ptr and raw pointer combination. And the way unique_ptr works internally.
Could some one please explain/answer based on my understanding as mentioned below, so that I can go ahead and use the smart pointers.
Below is the example:
class A
{
public:
void show()
{
cout<<"A::show()"<<endl;
}
};
int main()
{
unique_ptr<A> p1 (new A);
p1 -> show();
// returns the memory address of p1
cout << p1.get();
retrun 0;
}
From the above example,
When creating unique_ptr object "p1" we are providing raw pointer. Internally, unique_ptr constructor will initialize the unique_ptr with the raw pointer. Is my understanding correct?
As per the unique_ptr definition, "The pointer is exclusively owned by one object or a resource".
Based on the above statement, in our scenario, "raw pointer" is exclusively
owned by the unique_ptr object "p1". Am I correct?
And also after the statement, cout << p1.get(); (In the above sample program) as it is going out of scope, internally, the destructor of the unique_ptr called and it deletes the associated raw pointer. Is my understanding correct?
Finally, once deletes the associated raw pointer is the unique_ptr object will become empty?
When creating unique_ptr object "p1" we are providing raw pointer. Internally, unique_ptr constructor will initialize the unique_ptr with the raw pointer. Is my understanding correct?
Yes. The unique pointer will hold the same address.
As per the unique_ptr definition, "The pointer is exclusively owned by one object or a resource".
Based on the above statement, in our scenario, "raw pointer" is exclusively owned by the unique_ptr object "p1". Am I correct?
Yes. The only reference, the one that owns the resource and will free it, is the unique pointer. Note however that it's not the pointer that's owned, but the object it points at. The unique_ptr didn't take ownership of the raw pointer, it took ownership of the object (the resource) that is at the address the raw pointer provided.
And also after the statement, cout << p1.get(); (In the above sample program) as it is going out of scope, internally, the destructor of the unique_ptr called and it deletes the associated raw pointer. Is my understanding correct?
Yes. The unique ptr will cause the deletion of its internal raw pointer when it goes out of scope.
Finally, once deletes the associated raw pointer is the unique_ptr object will become empty?
Doesn't have to. Since the deletion happens when the unique_ptr object itself is being destroyed, there is no real need to "empty" it. It's about to go out of existence anyway, so its value is immaterial.
Recently, I was confused on why I continuously was faced with a segmentation fault trying to access an element in a vector of pointers of certain objects. I didn't manage to resolve the issue, but I suspect that it is because after I pushed the object pointer into a vector, I called delete on it, thinking that the vector stored a copy.
In the following code:
std::vector<SomeObject *> testvector;
SomeObject * testobject = new SomeObject(/* some arguments here, call constructor */)
testvector.push_back(testobject);
delete testobject; // does this affect the element in the vector?
The debugger confirms that the pointers getting added to the vector do indeed have proper data, but once I call delete on them, I'm unsure if the element inside the vector is affected. Does the vector store just a copy? When I call delete on the object, I suspect that delete is being called on the pointer in the vector, but I am unsure.
Now I tried to print out the data in the vector after calling delete, I get this: ??? ?? ???? ???
And I am assuming that the call to delete has affected the vector element. Is this the case? I thought that after I added the pointer to the vector, I could safely free the object without affecting the element in the vector, but it seems that I end up accessing memory that is no longer allocated. Does the call to delete affect the pointer in the vector?
"Does the call to delete affect the pointer in the vector?"
It doesn't affect the pointer. It affects the behavior invoked by using this pointer since the object it points to no longer exists. When you call delete, the object is deleted and whatever you try to do with that object using invalid (old, dangling) pointer, the behavior is undefined.
std::vector<SomeObject *> testvector;
SomeObject * testobject = new SomeObject()
testvector.push_back(testobject);
Constructs a vector of pointers, creates an instace of SomeObject and pushes an address of this object to your vector. Then when you call:
delete testobject;
There is no way how std::vector could know that the object has been deleted. Your vector still contains an old pointer, which has became invalid by the time the object was deleted. A possible solution could be using a vector of smart pointers such as shared_ptr, however at first you should consider whether you want to use a vector of pointers at first place. Maybe std::vector<SomeObject> would be more reasonable way to go.
The vector contains pointers not the objects theirself. So after deleting an object the corresponding pointer will be invalid.
When you copy a pointer, you only copy the address of the object, not the object itself. That means the pointer in your vector and your pointer outside the vector were still referring to the same thing when you called delete.
The reason the debugger may still have shown seemingly valid data is because the memory doesn't necessarily get overwritten when you delete something. It's simply marked as 'free' so that it can be used by something else later if required.
Yes, both testobject and the inserted element into the vector are pointing to a same address. After deleting one of them another will be a dangling pointer and dereferencing it is undefined behavior.
You can use smart pointers such as std::unique_ptr or std::shared_ptr.
std::vector<std::shared_ptr<SomeObject>> testvector;
std::shared_ptr<SomeObject> testobject(new SomeObject);
testvector.push_back(testobject);
or
std::vector<std::unique_ptr<SomeObject>> testvector;
std::unique_ptr<int> testobject(new SomeObject);
testvector.push_back(std::move(testobject));
// After `std::move` you can not use `testobject` anymore!
Basic Question: when does a program call a class' destructor method in C++? I have been told that it is called whenever an object goes out of scope or is subjected to a delete
More specific questions:
1) If the object is created via a pointer and that pointer is later deleted or given a new address to point to, does the object that it was pointing to call its destructor (assuming nothing else is pointing to it)?
2) Following up on question 1, what defines when an object goes out of scope (not regarding to when an object leaves a given {block}). So, in other words, when is a destructor called on an object in a linked list?
3) Would you ever want to call a destructor manually?
1) If the object is created via a pointer and that pointer is later deleted or given a new address to point to, does the object that it was pointing to call its destructor (assuming nothing else is pointing to it)?
It depends on the type of pointers. For example, smart pointers often delete their objects when they are deleted. Ordinary pointers do not. The same is true when a pointer is made to point to a different object. Some smart pointers will destroy the old object, or will destroy it if it has no more references. Ordinary pointers have no such smarts. They just hold an address and allow you to perform operations on the objects they point to by specifically doing so.
2) Following up on question 1, what defines when an object goes out of scope (not regarding to when an object leaves a given {block}). So, in other words, when is a destructor called on an object in a linked list?
That's up to the implementation of the linked list. Typical collections destroy all their contained objects when they are destroyed.
So, a linked list of pointers would typically destroy the pointers but not the objects they point to. (Which may be correct. They may be references by other pointers.) A linked list specifically designed to contain pointers, however, might delete the objects on its own destruction.
A linked list of smart pointers could automatically delete the objects when the pointers are deleted, or do so if they had no more references. It's all up to you to pick the pieces that do what you want.
3) Would you ever want to call a destructor manually?
Sure. One example would be if you want to replace an object with another object of the same type but don't want to free memory just to allocate it again. You can destroy the old object in place and construct a new one in place. (However, generally this is a bad idea.)
// pointer is destroyed because it goes out of scope,
// but not the object it pointed to. memory leak
if (1) {
Foo *myfoo = new Foo("foo");
}
// pointer is destroyed because it goes out of scope,
// object it points to is deleted. no memory leak
if(1) {
Foo *myfoo = new Foo("foo");
delete myfoo;
}
// no memory leak, object goes out of scope
if(1) {
Foo myfoo("foo");
}
Others have already addressed the other issues, so I'll just look at one point: do you ever want to manually delete an object.
The answer is yes. #DavidSchwartz gave one example, but it's a fairly unusual one. I'll give an example that's under the hood of what a lot of C++ programmers use all the time: std::vector (and std::deque, though it's not used quite as much).
As most people know, std::vector will allocate a larger block of memory when/if you add more items than its current allocation can hold. When it does this, however, it has a block of memory that's capable of holding more objects than are currently in the vector.
To manage that, what vector does under the covers is allocate raw memory via the Allocator object (which, unless you specify otherwise, means it uses ::operator new). Then, when you use (for example) push_back to add an item to the vector, internally the vector uses a placement new to create an item in the (previously) unused part of its memory space.
Now, what happens when/if you erase an item from the vector? It can't just use delete -- that would release its entire block of memory; it needs to destroy one object in that memory without destroying any others, or releasing any of the block of memory it controls (for example, if you erase 5 items from a vector, then immediately push_back 5 more items, it's guaranteed that the vector will not reallocate memory when you do so.
To do that, the vector directly destroys the objects in the memory by explicitly calling the destructor, not by using delete.
If, perchance, somebody else were to write a container using contiguous storage roughly like a vector does (or some variant of that, like std::deque really does), you'd almost certainly want to use the same technique.
Just for example, let's consider how you might write code for a circular ring-buffer.
#ifndef CBUFFER_H_INC
#define CBUFFER_H_INC
template <class T>
class circular_buffer {
T *data;
unsigned read_pos;
unsigned write_pos;
unsigned in_use;
const unsigned capacity;
public:
circular_buffer(unsigned size) :
data((T *)operator new(size * sizeof(T))),
read_pos(0),
write_pos(0),
in_use(0),
capacity(size)
{}
void push(T const &t) {
// ensure there's room in buffer:
if (in_use == capacity)
pop();
// construct copy of object in-place into buffer
new(&data[write_pos++]) T(t);
// keep pointer in bounds.
write_pos %= capacity;
++in_use;
}
// return oldest object in queue:
T front() {
return data[read_pos];
}
// remove oldest object from queue:
void pop() {
// destroy the object:
data[read_pos++].~T();
// keep pointer in bounds.
read_pos %= capacity;
--in_use;
}
~circular_buffer() {
// first destroy any content
while (in_use != 0)
pop();
// then release the buffer.
operator delete(data);
}
};
#endif
Unlike the standard containers, this uses operator new and operator delete directly. For real use, you probably do want to use an allocator class, but for the moment it would do more to distract than contribute (IMO, anyway).
When you create an object with new, you are responsible for calling delete. When you create an object with make_shared, the resulting shared_ptr is responsible for keeping count and calling delete when the use count goes to zero.
Going out of scope does mean leaving a block. This is when the destructor is called, assuming that the object was not allocated with new (i.e. it is a stack object).
About the only time when you need to call a destructor explicitly is when you allocate the object with a placement new.
1) Objects are not created 'via pointers'. There is a pointer that is assigned to any object you 'new'. Assuming this is what you mean, if you call 'delete' on the pointer, it will actually delete (and call the destructor on) the object the pointer dereferences. If you assign the pointer to another object there will be a memory leak; nothing in C++ will collect your garbage for you.
2) These are two separate questions. A variable goes out of scope when the stack frame it's declared in is popped off the stack. Usually this is when you leave a block. Objects in a heap never go out of scope, though their pointers on the stack may. Nothing in particular guarantees that a destructor of an object in a linked list will be called.
3) Not really. There may be Deep Magic that would suggest otherwise, but typically you want to match up your 'new' keywords with your 'delete' keywords, and put everything in your destructor necessary to make sure it properly cleans itself up. If you don't do this, be sure to comment the destructor with specific instructions to anyone using the class on how they should clean up that object's resources manually.
Pointers -- Regular pointers don't support RAII. Without an explicit delete, there will be garbage. Fortunately C++ has auto pointers that handle this for you!
Scope -- Think of when a variable becomes invisible to your program. Usually this is at the end of {block}, as you point out.
Manual destruction -- Never attempt this. Just let scope and RAII do the magic for you.
To give a detailed answer to question 3: yes, there are (rare) occasions when you might call the destructor explicitly, in particular as the counterpart to a placement new, as dasblinkenlight observes.
To give a concrete example of this:
#include <iostream>
#include <new>
struct Foo
{
Foo(int i_) : i(i_) {}
int i;
};
int main()
{
// Allocate a chunk of memory large enough to hold 5 Foo objects.
int n = 5;
char *chunk = static_cast<char*>(::operator new(sizeof(Foo) * n));
// Use placement new to construct Foo instances at the right places in the chunk.
for(int i=0; i<n; ++i)
{
new (chunk + i*sizeof(Foo)) Foo(i);
}
// Output the contents of each Foo instance and use an explicit destructor call to destroy it.
for(int i=0; i<n; ++i)
{
Foo *foo = reinterpret_cast<Foo*>(chunk + i*sizeof(Foo));
std::cout << foo->i << '\n';
foo->~Foo();
}
// Deallocate the original chunk of memory.
::operator delete(chunk);
return 0;
}
The purpose of this kind of thing is to decouple memory allocation from object construction.
Remember that Constructor of an object is called immediately after the memory is allocated for that object and whereas the destructor is called just before deallocating the memory of that object.
Whenever you use "new", that is, attach an address to a pointer, or to say, you claim space on the heap, you need to "delete" it.
1.yes, when you delete something, the destructor is called.
2.When the destructor of the linked list is called, it's objects' destructor is called. But if they are pointers, you need to delete them manually.
3.when the space is claimed by "new".
Yes, a destructor (a.k.a. dtor) is called when an object goes out of scope if it is on the stack or when you call delete on a pointer to an object.
If the pointer is deleted via delete then the dtor will be called. If you reassign the pointer without calling delete first, you will get a memory leak because the object still exists in memory somewhere. In the latter instance, the dtor is not called.
A good linked list implementation will call the dtor of all objects in the list when the list is being destroyed (because you either called some method to destory it or it went out of scope itself). This is implementation dependent.
I doubt it, but I wouldn't be surprised if there is some odd circumstance out there.
If the object is created not via a pointer(for example,A a1 = A();),the destructor is called when the object is destructed, always when the function where the object lies is finished.for example:
void func()
{
...
A a1 = A();
...
}//finish
the destructor is called when code is execused to line "finish".
If the object is created via a pointer(for example,A * a2 = new A();),the destructor is called when the pointer is deleted(delete a2;).If the point is not deleted by user explictly or given a new address before deleting it, the memory leak is occured. That is a bug.
In a linked list, if we use std::list<>, we needn't care about the desctructor or memory leak because std::list<> has finished all of these for us. In a linked list written by ourselves, we should write the desctructor and delete the pointer explictly.Otherwise, it will cause memory leak.
We rarely call a destructor manually. It is a function providing for the system.
Sorry for my poor English!
Object object = *(queue.dequeue());
queue is a QQueue<Object*>. i'm concerned that the dequeued pointer is deleted before i dereference it. of course i can access object's data but that doesn't mean anything. doing it all in one line like this is convenient (i don't want a pointer because i want object to be deleted automatically when it goes out of scope) but if it's not safe then i can't do it. please advise. thanks.
It isn't immediately unsafe per se, but chances are you'll be using it wrong.
All your code does is make a copy of the element pointed to by the last element of queue. By dequeuing the element, you lose the pointer to it, and you now have no way of freeing that original object in case it was dynamically constructed.
Correct example (no dynamic objects, no leak):
QQueue<Foo*> q;
{
Foo a;
q.enqueue(&a);
Foo b = *q.dequeue();
}
Broken example (dynamic object leaked):
QQueue<Foo*> q;
q.enqueue(new Foo); // eeew, naked "new" in C++...
Foo c = *q.dequeue();
// now the newed element is leaked
You're right that c is safely destroyed at the end of its scope, but you're leaking the orginal, new'ed object, to which you have no pointer or reference now.