I've read the post: Why do we need to set rvalue reference to null in move constructor?
It said that during a move, you just copied the pointer from one object to another, so two pointers points to the temporary object. And when the temporary object goes out of scope, its destructor will run. And then the object pointed by 2 pointers would be deallocates. So the pointer field of object constructed by move constructor would point to unavailable place.
However, look at following code:
int *p = new int(3);
int *q = p;
delete p;
std::cout << *q << std::endl;
after delete the pointer p, pointer q could still access the int object.
So, is that just because when the object is accessed by rvalue reference causes the difference?
No you can't. It appears to work, but it's entirely undefined behavior. The memory is released to the runtime.
When you move something, you're effectively saying the original object is no longer valid - you only access its original contents from the moved-to object. Furthermore, the set to NULL after a move prevents a double-delete - when the original objects goes out of scope and attempts to free that memory, it will either fail straight away (if the new object already free'd it) or the new object will fail when it itself attempts to release that memory.
Accessing deleted memory of the free store is undefined behavior.
On move construction, the pointer of the object constructed is set to the pointer of the rvalue, which in turn is set to nullptr afterwards.
The object referenced by the rvalue ends its lifetime thereafter, after all it is a temporary. Therefore, the pointer set to nullptr is not expected to be used anymore. When it is destructed, delete nullptr; is executed, i.e., a no-op.
OTOH, when the lifetime of the constructed object ends, the actual resource is deleted - the pointer to it was assigned in the move constructor.
No, after delete the pointer p, pointer q cannot still access the int object. If you think otherwise because you ran it and got 3 in the output--that's because you caused undefined behavior and UB can "work" as one of its many, many options.
In general what happens is that the memory address hasn't been reused yet, still belongs to the program (so it has permission to access and the value has not been erased), so you'll see whatever value was deleted in that memory. All this means that it will appear as if the code is perfectly OK when it's not. You could also print using *p in this case and it would be no different. The p and q variables both contain the same address...which was freed by a delete.
One interesting aspect of this is that high security applications, or encryption applications like GPG, manually fill deleted memory with garbage so that it can't just be sniffed out--giving access to private keys out to the world. Otherwise the key would still just be written in RAM until someone writes something else there!
This is the problem with pointers. They do not convey ownership semantics.
You should be using something like std::unique_ptr. When you move the pointer from one object to another the old object recognizes it no longer owns the object and thus you can;t access the data.
Simple solution. Like the rest of the C++ community stop using pointers like this.
std::unqieu_ptr<int> p(new int(3));
std::unique_ptr<int> q = p; // Fails to compile
std::unqieu_ptr<int> p(new int(3));
std::unique_ptr<int> q = std::move(p); // explicitly transfer ownership.
// delete p; // No longer need this as when the onbject goes out of scope
// it is deleted.
Both the question you linked and your question is trying to avoid undefined behavior upon dereferencing of q.
The thing is that, (in the linked question) you have to know that you can't dereference q anymore (you aren't managing it) by setting it to nullptr. But here, it's your business to not to dereference q after the delete. It's extremely predictable that q will be deleted before std::cout << *q << std::endl;. It's your fault that you're dereferencing it!
Nevertheless, setting q to nullptr helps with debugging, delete q is no longer UB, and nullptr signifies a pointer to non-existent object.
Related
I wanted to ask like we can do with a pointer.
int q = 10;
int* p = &q;
How to do something with a shared_ptr? Can I use make_shared<> here?
shared_ptr<int> r = make_shared<int>(q);
Is this correct?
If you want a shared_ptr that owns a pointer, use the constructor directly:
std::shared_ptr<int> r(some_pointer_to_int);
If you want a shared_ptr that points to a copy of a given object, use make_shared:
auto r = std::make_shared<int>(some_int);
Note that the former would NOT be correct if the pointer points to an object with automatic storage duration. Such objects are managed by the runtime.
No it is not. Smart pointer is here for guaranteed deletion of the pointer(handle) around which it wraps. In your example you just take address of the local stack variable. Deletion of such a variable is undefined behavior(your app will crash most of the time).
But if your actual code is different and you truly want to keep an existing pointer(which is ok to delete later) in the shared_ptr you should do the following:
shared_ptr<int> r{q};
make_shared exists as a helper for creating shared_ptr passing arguments to the object the pointer is going to point to.
The point of smart pointers is to maintain their memory smartly. In your case q is located on the stack. If you pass it to a smart pointer then it will get deleted when it is no longer referenced. This will crash your program because you can't delete memory on the stack. It is also sort of silly to want to because it is freed when q goes out of scope anyway.
make_shared<>() takes the arguments to a constructor.
shared_ptr<int> r = make_shared<int>(q);
This constructs a shared point to a single int that holds the same value as q.
If you want to assign a pointer to a shared pointer you would do something like:
shared_ptr<int> r = q;
That being said, your particular example makes no sense. When the shared pointer goes out of scope it will call delete on a stack allocated variable with invokes undefined behavior.
Without any usage information it depends upon the lifetime. If you only need to use it during a function, you're better off with a reference.
auto& r = *q;
If you must get a pointer type you can do
auto& r = q;
I am wondering what will hapen if I try to do a delete on a pointer that is already deleted, or may have not been allocated ? I've read two things : first, that delete operator will do some checkings and we do not need to check if the pointer is null ; and then, I read that it can lead to unknown behaviors..
I'm asking it, because I use some personal objects that contains Qt objects attributes ; I think that Qt delete all widgets associated when we close the window, but I'm not pretty sure and still : if the soft crash before the window's close, we have to delete all objects manually.
So, what would be the best solution ? Something like that ?
if( my_object )
delete my_object;
Can it avoid dangerous behaviours ?
delete on an already deleted non-null pointer is undefined behavior - your program will likely crash. You can safely use delete on a null pointer - it will yield a no-op.
So the real problem is not delete on a null pointer. The real problem is here:
ptr = new Something();
otherPtr = ptr;
delete ptr;
delete otherPtr;
This can happen if you have several pointers to the same object and it is quite dangerous. The possible solutions are:
use smart pointers (no delete in your code) or
only have one designated pointer for controlling each object lifetime and delete at exactly the right time.
if( my_object )
delete my_object;
is redundant. delete on a NULL pointer does nothing. This is guaranteed by the standard.
delete on a pointer that was already deleted causes undefined behavior. That's why you should always remember to assign your pointers to NULL after you delete them:
delete p;
p = NULL;
EDIT: As per the comments, I feel I should specify this. If you have multiple pointers to the same object, the assignment to NULL won't make the delete safe. Regardless, it's better to use smart pointers.
Please note that deleting a pointer does not set it to NULL.
int* i = new int;
*i = 42;
delete i;
delete i; // oops! i is still pointing to the same memory, but it has been deleted already
Deleting a null pointer doesn't do anything, deleting an already deleted object will result in undefined behaviour.
the right way is:
if( my_object )
{
delete my_object;
my_object = NULL;
}
because, calling twice the way it was before will call delete on a deleted pointer.
It results in Undefined Behavior if you call delete on already deleted pointer.
Calling delete on a NULL pointer has no-effect though.
Standard c++03 ยง 3.7.4.2-3
If a deallocation function terminates by throwing an exception, the behavior is undefined. The value of the first argument supplied to a deallocation function may be a null pointer value; if so, and if the deallocation function is one supplied in the standard library, the call has no effect. Otherwise, the value supplied
to operator delete(void*) in the standard library shall be one of the values returned by a previous invocation of either operator new(std::size_t) or operator new(std::size_t, const std::nothrow_-t&) in the standard library, and the value supplied to operator delete[](void*) in the standard library shall be one of the values returned by a previous invocation of either operator new[](std::size_t) or
operator new[](std::size_t, const std::nothrow_t&) in the standard library.
Using RAII & Smart Pointers are your best weapons to avoid such problems.
Just to combine the answers above:
if (my_object) checks the value of the pointer, not the existence of the object. If it is already deleted, the pointer may still point to that location.
deleting an already deleted object is undefined behavior and will probably crash your program.
deleting NULL is defined and does nothing. Together with point 1 this explains the answer of Luchian.
To sum it up: You have to be clear on who owns the object and where the different pointer to the object are. When you delete an object, make sure to set all pointer pointing to that location to 0/NULL. Use managing objects like boost::shared_pointer or QPointer to help you in this task.
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.
I have a class with a vector of pointers to objects. I've introduced some elements on this vector, and on my main file I've managed to print them and add others with no problems. Now I'm trying to remove an element from that vector and check to see if it's not NULL but it is not working.
I'm filling it with on class Test:
Other *a = new Other(1,1);
Other *b = new Other(2,2);
Other *c = new Other(3,3);
v->push_back(a);
v->push_back(b);
v->push_back(c);
And on my main file I have:
Test t;
(...)
Other *pointer = t.vect->at(0);
delete t.vect->at(0);
t.vect->erase(t.vect->begin());
if (pointer == NULL) { cout << "Nothing here.."; } // Never enters here..
Deleting a pointer doesn't have to zero it, it just frees the memory assigned there. Using pointer is undefined after the delete though, as the memory is free to be used for other things. Technically the C++ spec intentionally leaves it up to implementations whether they want to zero a deleted pointer or not, but practically none that I know of do so
The deletion of memory pointed by a pointer, doesn't set the pointer to NULL.
You set pointer equal to the address of something, and never touched it again, so of course it won't be null. The fact that you then did something to the object is irrelevant.
Using simple pointers, there is no safe way for pointer to determine whether the object it once pointed to has been deleted. The simplest way to do what you seem to want to do is by leaving it to the containers: if you're interested in that object, search for pointer in the vector to see whether it's still there (and don't delete the object without erasing the corresponding element from the vector, or you'll have the same problem all over again).
To overcome the checking a deleted ptr problem you could use boost::shared_ptr.
Instead of delete use .reset() and to check if the ptr is still valid use .get()
(Actually you can just use if(p) where p is the shared_ptr because it has a conversion to bool)
Using C++:
I currently have a method in which if an event occurs an object is created, and a pointer to that object is stored in a vector of pointers to objects of that class. However, since objects are destroyed once the local scope ends, does this mean that the pointer I stored to the object in the vector is now null or undefined? If so, are there any general ways to get around this - I'm assuming the best way would be to allocate on the heap.
I ask this because when I try to access the vector and do operations on the contents I am getting odd behavior, and I'm not sure if this could be the cause or if it's something totally unrelated.
It depends on how you allocate the object. If you allocate the object as an auto variable, (i.e. on the stack), then any pointer to that object will become invalid once the object goes out of scope, and so dereferencing the pointer will lead to undefined behavior.
For example:
Object* pointer;
{
Object myobject;
pointer = &myobject;
}
pointer->doSomething(); // <--- INVALID! myobject is now out of scope
If, however, you allocate the object on the Heap, using the new operator, then the object will remain valid even after you exit the local scope. However, remember that there is no automatic garbage collection in C++, and so you must remember to delete the object or you will have a memory leak.
So if I understand correctly you have described the following scenario:
class MyClass
{
public:
int a;
SomeOtherClass b;
};
void Test()
{
std::vector<MyClass*> v;
for (int i=0; i < 10; ++i)
{
MyClass b;
v.push_back(&b);
}
// now v holds 10 items pointers to strange and scary places.
}
This is definitely bad.
There are two primary alternatives:
allocate the objects on the heap using new.
make the vector hold instances of MyClass (i.e. std::vector<MyClass>)
I generally prefer the second option when possible. This is because I don't have to worry about manually deallocating memory, the vector does it for me. It is also often more efficient. The only problem, is that I would have to be sure to create a copy constructor for MyClass. That means a constructor of the form MyClass(const MyClass& other) { ... }.
If you store a pointer to an object, and that object is destroyed (e.g. goes out of scope), that pointer will not be null, but if you try to use it you will get undefined behavior. So if one of the pointers in your vector points to a stack-allocated object, and that object goes out of scope, that pointer will become impossible to use safely. In particular, there's no way to tell whether a pointer points to a valid object or not; you just have to write your program in such a way that pointers never ever ever point to destroyed objects.
To get around this, you can use new to allocate space for your object on the heap. Then it won't be destroyed until you delete it. However, this takes a little care to get right as you have to make sure that your object isn't destroyed too early (leaving another 'dangling pointer' problem like the one you have now) or too late (creating a memory leak).
To get around that, the common approach in C++ is to use what's called (with varying degrees of accuracy) a smart pointer. If you're new to C++ you probably shouldn't worry about these yet, but if you're feeling ambitious (or frustrated with memory corruption bugs), check out shared_ptr from the Boost library.
If you have a local variable, such as an int counter, then it will be out of scope when you exit the function, but, unless you have a C++ with a garbage collector, then your pointer will be in scope, as you have some global vector that points to your object, as long as you did a new for the pointer.
I haven't seen a situation where I have done new and my memory was freed without me doing anything.
To check (in no particular order):
Did you hit an exception during construction of member objects whose pointers you store?
Do you have a null-pointer in the container that you dereference?
Are you using the vector object after it goes out of scope? (Looks unlikely, but I still have to ask.)
Are you cleaning up properly?
Here's a sample to help you along:
void SomeClass::Erase(std::vector<YourType*> &a)
{
for( size_t i = 0; i < a.size(); i++ ) delete a[i];
a.clear();
}