I'm a bit curious about a pointer's behaviour in C++. So I have this little program to test out and unfortunately it run well.
#include <iostream>
class Test{
public:
Test(){
std::cout<<"Test Created!\n";
}
~Test(){
std::cout<<"Test Destroyed!\n";
}
};
void destroyer(Test* T){
Test* temp = T;
delete temp;
}
int main(){
Test* ptr = new Test();
destroyer(ptr);
}
And it gives in return
Test Created!
Test Destroyed!
And I draw the conclusion that when we delete a pointer, actually it just deletes the object that the pointer refers to, not the variable itself (variable pointer will automatically deleted at the end of program, same as other primitive data type). Is my thought about this true?
Yes, the delete operator only calls the destructor and frees the memory occupied by the object that the pointer points to. The pointer itself is a local variable like any other and cannot be (and does not need to be) deleted.
It may be worth noting that calling delete ptr; does not change the value of ptr, so after deleting the pointer ptr would point to memory that has been deallocated. It would be undefined behaviour to access that memory after deleting it.
delete is an operator that looks at the object pointed to by the pointer object. The pointer variable is still a local value whose lifetime is tied to the scope it is declared in.
You have 3 pointer objects, with differing lifetimes. Only ptr in main lasts to the end of the program. T and temp only exist during destroyer.
Colloquially we say "delete the pointer" when we write
delete x;
However, this isnt quite accurate. What is deleted is the object pointed to by x.
And i have conclusion that when we delete pointer, actually it just delete the object that pointer refer to not the variable itself (variable pointer will automatically deleted at the end of program, same as other primitive data type). Is my thought about this true?
Yes.
In practice the inaccuracy mentioned above is just fine because after deleting the object the pointer value cannot be used without invoking either implementation defined or undefined behavior and that also affects other pointers to the same object:
int* x = new int(42);
int* y = x;
detele x;
std::cout << x << y; // implementation defined
std::cout << *x << *y; // undefined
x = new int(42); // OK
For details see here.
Related
If I don't use delete ptr at comment here in below code, then it causes a memory leak?
int *create(){
int a;
int *a_ptr{&a};
return a_ptr;
}
int main(){
int *ptr = {nullptr};
ptr = create();
//here
return 0;
}
Actually you return pointer to object that is destroyed after create function ends its execution.
int a; is created on stack so a_ptr points to some place on stack. During return all objects on stack are destroyed and there is only a_ptr left there as value.
No, you don't have memory leak but ptr in main() function is invalid as points to non-existing object.
In main() scope you initialized a pointer to nullptr without allocating any space (You have not used the new keyword).
In create() function you declared an int without initializing it (it could have any value), then you declared a a_ptr pointing to the reference of a.
When the code exits from the create() function scope, the variable a is out of scope and those memory cells will be marked as unused. So, when the returned pointer it's assigned to the ptr in main() scope it will points to unused memory and this will lead to undefined behaviour whenever you use this pointer.
Essentialy, the pointer is already pointing to nullptr and you don't have to delete it, because you haven't allocated any space for the pointer and you have nothing to delete.
No, you must only delete pointers that were created by new. Never delete pointers to local variables. However, your code has undefined behaviour and that should be your primary concern.
When create() returns, the lifetime of it's local variable a will end and any pointers/references to it will become invalid. Accessing such an invalid pointer causes undefined behaviour which often manifests as segmentation fault. Never return pointers or references to local variables from a function.
One option is to actually new the pointer you return:
int *create(){
return new int{0};
}
int main(){
int *ptr = create();
delete ptr;
}
I wouldn't recommend this however. In modern C++ you can and should avoid new/delete/new[]/delete[] and prefer smart pointers or vectors as appropriate.
If I don't use delete ptr at comment here in below code, then it causes a memory leak?
No. Variables with automatic storage duration are destroyed automatically when they go out of scope. There is no memory leak in the example.
However if you do delete the ptr then the behaviour of the program will be undefined. That's because you may delete only what you've allocated with new.
Even if you only indirect through the pointer, will the program be undefined. The returned pointer is always invalid and nothing useful can be done with it.
To avoid keep having to use -> and instead work directly with the object, is it acceptable practice to do:
obj x = *(new obj(...));
...
delete &obj;
This is not just poor practice, but:
Leaking memory (most likely, unless you are using some pattern that is not visible from the code you provided), since obj will store a copy of the original object created by the new expression, and the pointer to that object returned by new is lost;
Most importantly, undefined behavior, since you are passing to delete a pointer to an object that was not allocated with new. Per paragraph 5.3.5/2 of the C++11 Standard:
[...] In the first alternative (delete object), the value of the operand of delete may be a null pointer
value, a pointer to a non-array object created by a previous new-expression, or a pointer to a subobject (1.8)
representing a base class of such an object (Clause 10). If not, the behavior is undefined.
No, and in fact this leads to a leak. x is copy initialized, so the original object pointed to by new obj is lost.
Just use
obj x(...);
No need for dynamic allocation. Or
obj x = obj(...);
if you must (doubt it).
Certainly not; that copies the dynamic object to an automatic variable, loses the only pointer to it, and then attempts to delete the automatic copy. You've got a memory leak and an invalid deletion.
Much better would be to use an automatic variable in the first place:
obj x(...);
...
// no need to delete anything
or, if it really must be dynamic for some reason (because it's too big for the stack, or you don't always want to destroy it here), then use a smart pointer, and a reference if you really don't like ->
std::unique_ptr<obj> p(new obj(...));
obj & x = *p;
...
// still no need to delete anything
Changing your x into a reference would be valid (as long as you're careful that exceptions, early function returns, etc. won't cause a leak), but would cause howls of confusion among anyone unfortunate enough to have to maintain it.
You cannot delete your object properly if you do it like that.
Implicitly you do the following.
class A
{
public:
int test (void) { return 1; }
};
int main (void)
{
A * p = new A;
A v(*p);
//...
delete &v; // &v != p and v is not constructed via new!
return 0;
}
If you want to work with an object-like-syntax you can bind a reference to the object.
class A
{
public:
int test (void) { return 1; }
};
int main (void)
{
A * p = new A;
A & r = *p;
int i = r.test();
delete p;
return 0;
}
If you delete your object through the same pointer, there will be no leak.
I'm working on a project for class and I'm using classes and pointers of type class to call some functions in the class but it's crashing on Code Blocks and Eclipse and I don't know what is going on
Note it crashes when assigning x with y
#include <iostream>
using namespace std;
class a{
private:
int x;
public:
void set_X(int y){
x=y;
}
};
int main()
{
a *Ptr;
Ptr->set_X(5);
}
a *Ptr;
Ptr->set_X(5);
Your Ptr does not point to anything. Trying to invoke a member function on an uninitialised pointer results in undefined behaviour. Crashing is just one of the many more or less random things that can happen.
Luckily, in your example, you do not need a pointer anyway. You can simply write:
a my_a;
my_a.set_X(5);
Pointers often point to dynamically allocated objects. If this is what you want, you must use new and delete accordingly:
a *Ptr = new a;
Ptr->set_X(5);
delete Ptr;
In modern C++, std::unique_ptr is typically a superior alternative because you don't have to manually release the allocated memory, which removes a lot of potential programming errors:
auto Ptr = std::make_unique<a>();
Ptr->set_X(5);
// no delete necessary
Basic rule: creating a pointer (a variable that contains the address of an object, or otherwise is NULL (or nullptr since 2011)) as pointed out by Christian Hackl in comments) does not create a corresponding pointee (an object who's address can be stored in the pointer).
More formally, Ptr is an uninitialised pointer. Even accessing its value gives undefined behaviour (e.g. some_other_pointer = Ptr). For operator -> to work correctly, the pointer must first be initialised so it points at a valid object.
a aobj;
a *Ptr = &aobj;
Ptr->set_X(42); // OK
a *Ptr2 = new a;
Ptr2->set_X(42); // OK
delete Ptr2;
You have just declared a pointer variable of type a* but it doesn't point to a valid memory address. And since you are calling a member function via that pointer which updates a data-member hence you have segfault because this pointer is NULL.
You must initialize pointer with some valid memory address of class a object.
Following can be done,
a* ptr = new a;
ptr->set_X(5);
// ...
delete ptr;
In this case. It would be better that you should use some smart_ptr like std::shared_ptr or std::unique_ptr so that you don't need to worry about releasing resources manually.
Or
a* ptr;
a aobj_;
ptr = &aobj_;
ptr->set_X(5);
To avoid keep having to use -> and instead work directly with the object, is it acceptable practice to do:
obj x = *(new obj(...));
...
delete &obj;
This is not just poor practice, but:
Leaking memory (most likely, unless you are using some pattern that is not visible from the code you provided), since obj will store a copy of the original object created by the new expression, and the pointer to that object returned by new is lost;
Most importantly, undefined behavior, since you are passing to delete a pointer to an object that was not allocated with new. Per paragraph 5.3.5/2 of the C++11 Standard:
[...] In the first alternative (delete object), the value of the operand of delete may be a null pointer
value, a pointer to a non-array object created by a previous new-expression, or a pointer to a subobject (1.8)
representing a base class of such an object (Clause 10). If not, the behavior is undefined.
No, and in fact this leads to a leak. x is copy initialized, so the original object pointed to by new obj is lost.
Just use
obj x(...);
No need for dynamic allocation. Or
obj x = obj(...);
if you must (doubt it).
Certainly not; that copies the dynamic object to an automatic variable, loses the only pointer to it, and then attempts to delete the automatic copy. You've got a memory leak and an invalid deletion.
Much better would be to use an automatic variable in the first place:
obj x(...);
...
// no need to delete anything
or, if it really must be dynamic for some reason (because it's too big for the stack, or you don't always want to destroy it here), then use a smart pointer, and a reference if you really don't like ->
std::unique_ptr<obj> p(new obj(...));
obj & x = *p;
...
// still no need to delete anything
Changing your x into a reference would be valid (as long as you're careful that exceptions, early function returns, etc. won't cause a leak), but would cause howls of confusion among anyone unfortunate enough to have to maintain it.
You cannot delete your object properly if you do it like that.
Implicitly you do the following.
class A
{
public:
int test (void) { return 1; }
};
int main (void)
{
A * p = new A;
A v(*p);
//...
delete &v; // &v != p and v is not constructed via new!
return 0;
}
If you want to work with an object-like-syntax you can bind a reference to the object.
class A
{
public:
int test (void) { return 1; }
};
int main (void)
{
A * p = new A;
A & r = *p;
int i = r.test();
delete p;
return 0;
}
If you delete your object through the same pointer, there will be no leak.
in the following code:
class x
{
private:
someRef& m_ref;
public:
x(someRef& someRef):m_ref(someRef)
{
}
do I need to do:
~x()
{
delete m_ref;
}
which by the way doesnt work without getting the pointer...
basically I'm asking: Do I need to call a destructor on a reference member?
No.
You only need to delete an object if you own it. If you were passed a reference, it means that someone else owns it, thus it's unnecessary and thankfully the language prevents it.
I don't think one actually strictly speaking ever deletes even pointers. What you delete are dynamically allocated objects (or arrays of objects) that the pointer is a handle for. If the object originates from a call to new and it is the responsibility of this class to clean up after this object, then you call delete.
It is technically possible that a reference might be referring to a dynamically allocated object:
int main()
{
//in principle a reference can also refer to a dynamically allocated object
x var(*new someRef);
}
//and if that is the intended usage:
x::~x()
{
delete &m_ref;
}
However, this would be incredibly bad style. By convention, the "owning" handle of a dynamically allocated object should not be a reference.
No. You can only delete pointers, not references, and even then you must only delete objects that you allocated using the new operator. And then you must be sure to delete them only once. Here is the case in which you would need to use delete in your destructor:
class x
{
private:
someObj* m_ptr;
public:
x():m_ptr(new someObj())
{
}
~x()
{
delete m_ptr;
}
But in general it's best to avoid even this and use smart pointers instead.
I want to clarify some misconceptions you seem to have that are beyond the intent of your question:
When a class's destructor is called all of it's members' destructors get called as well.
Calling delete is not the same as calling the destructor. delete explicitly calls the destructor and also calls operator delete at the objects location, it is a 2 part thing.
For a small bit of extra clarification I want to offer the following:
int *pi = new int;
//int& ir = pi; // can't do
// this a reference to the pointer but it is an error
// because or the type difference int& vs int* and
// static_cast won't help. reinterpret_cast would allow
// the assignment to take place but not help the 'delete ir'
int& ir = *pi; // this is OK - a reference to what the pointer points to.
// In other words, the the address of the int on the heap.
//delete ir; // can't do, it is a reference and you can't delete non-pointers.
delete &ir; // this works but it is still not "deleting a reference".
// The reference 'ir' is another name for the heap-based int.
// So, &ir is the address of that int, essentially a pointer.
// It is a pointer that is being used by delete, not a reference.