Does this piece of code lead to dangling pointer. My guess is no.
class Sample
{
public:
int *ptr;
Sample(int i)
{
ptr = new int(i);
}
~Sample()
{
delete ptr;
}
void PrintVal()
{
cout << "The value is " << *ptr;
}
};
void SomeFunc(Sample x)
{
cout << "Say i am in someFunc " << endl;
}
int main()
{
Sample s1 = 10;
SomeFunc(s1);
s1.PrintVal();
}
Yes. Sample's copy constructor gets called when you pass s1 to SomeFunc. The default copy constructor does a shallow copy, so ptr will get deleted twice.
Yes, as user said.
~Sample() {
delete ptr; // Pointer deleted but left dangling
ptr = NULL; // Pointer is no longer dangling
}
Note however, that any pointers you copied that pointer to will be left dangling unless they are set to NULL as well.
When you pass the object to SomeFunc() by value, shallow copy is taking place and after its execution, the memory ptr was pointing to has been deleted...
so when you call the PrintVal () function on s1 and try to dereference the pointer, your program may crash at this stage.... you can delete a pointer once and its memory becomes out of your control
Related
As the following code presents, I tried to delete the object by the raw pointer get from a unique_ptr. But, as the output shows, the complier reported errors. However, for raw pointers, we can do this int *p1 = new int{100}; int* p2 = p1; delete p2;.
Besides, I thought that unique_ptr maintain its ownership by move semantics. As the get() function of unique_ptr returns the raw pointer, how does the unique_ptr can still have the ownership of the object. Meanwhile, why the raw pointer doesn't get the ownership. At the same time, I am confusing how does this implemented. Thanks.
#include <iostream>
#include <memory>
int main(int argc, char const *argv[])
{
std::unique_ptr<int> newPtr = std::make_unique<int>(1234);
std::cout << *newPtr << std::endl;
int* rawInt = newPtr.get();
*rawInt = 200;
delete rawInt;
rawInt = nullptr;
std::cout << *newPtr << std::endl;
return 0;
}
The code was performed on MacOs and the output is:
std::unique_ptr is a really simple class. Conceptually, it's basically just this:
template <typename T>
class unique_ptr
{
private:
T* ptr;
public:
unique_ptr(T* p) ptr{p} {}
~unique_ptr() { delete ptr; }
T* get() { return ptr; }
T* release() {
T* p = ptr;
ptr = nullptr;
return p;
}
// other stuff
};
It just has a pointer member, and deletes the pointed-to object in its destructor. In reality there's a bit more to it, but that's essentially it.
The get member just returns a copy of the unique_ptr's managed pointer. That's it. Since the unique_ptr's pointer member is still pointing to that object, its destructor will still delete the object. If you also delete that object via another pointer to it then it will get deleted twice, which results in undefined behavior.
The release member function, on the other hand, sets the unique_ptr's pointer member to nullptr before returning a copy of its original value. Since its member pointer is null, its destructor won't delete anything.
I was experimenting with using unique_ptr and wrote some simple code to check how it works with move semantics.
#include <iostream>
#include <vector>
using namespace std;
class X
{
public:
X(){}
~X() { cout << "Destructor X" << endl; }
void Print() { cout << "X" << endl; }
};
int main()
{
unique_ptr<X> ptr(new X());
ptr->Print();
vector<unique_ptr<X>> v;
v.push_back(move(ptr));
ptr->Print();
v.front()->Print();
return 0;
}
The output is as follows:
X
X
X
Destructor X
My expectation was that the original unique_ptr ptr would be invalidated after the push_back. But the Print() method is called just fine. What would be the explanation for this behavior?
My expectation was that the original unique_ptr ptr would be invalidated after the push_back.
It's set to a null pointer. You can check that by comparing it to nullptr.
But the Print() method is called just fine. What would be the explanation for this behavior?
You're calling a member function on a null pointer, which is undefined behaviour. That member function doesn't actually access any data in the class, so it doesn't crash, but it's still undefined behaviour.
You get similar behaviour for this program, it has nothing to do with unique_ptr:
int main()
{
X x;
X* ptr = &x;
ptr->Print();
ptr = nullptr;
ptr->Print();
}
It appears to work fine because X::Print() doesn't actually read anything from the this pointer. If you change the definition of X::Print() to access some member data in the class you'll probably get a crash due to dereferencing a null pointer.
See When does invoking a member function on a null instance result in undefined behavior? for more information.
What you have is plain undefined behavior. If I replace the contents of main with the following
int main()
{
unique_ptr<X> ptr;
ptr->Print();
cout << (static_cast<bool>(ptr) ? "active\n" : "inactive\n");
}
Both gcc and clang still print
X
inactive
You're calling a member function on a nullptr, and I'm guessing it just happens to work because the member function doesn't actually make use of the this pointer. Change your class definition to:
class X
{
int y = 0;
public:
X(){}
~X() { cout << "Destructor X" << endl; }
void Print() { cout << "y = " << y << endl; }
};
Now your original code should result in a segmentation fault because it'll attempt to dereference nullptr.
As for your expectation that unique_ptr will be invalidated after you move from it, you're absolutely correct. This is guaranteed by the standard.
§20.8.1/4 [unique.ptr]
Additionally, u can, upon request, transfer ownership to another unique pointer u2. Upon completion of such a transfer, the following postconditions hold:
— u2.p is equal to the pre-transfer u.p,
— u.p is equal to nullptr, and
...
Above u & u2 are unique_ptr objects, and p is the pointer to the managed object.
I have the following code
#include <iostream>
struct mystruct
{
float x;
};
void fun(mystruct* ptr)
{
mystruct str = {10};
ptr = &str;
std::cout<<"bbq";
}
class cls
{
public:
mystruct* ptr;
void fun()
{
mystruct str = {10};
ptr = &str;
std::cout<<"bbq";
}
};
int main()
{
mystruct* ptr = new mystruct;
fun(ptr);
std::cout<<"bbq";
cls obj;
obj.fun();
std::cout<<"bbq";
}
At first pointer ptr is set in function fun to address of local structure. When function returns local structure gets destroyed as expected.
But then there is method in class that does the same with member pointer, but after method retrurns and im back in main member pointer is still set. Aren't method local variables destroyed after method returns ?
Your first example isn't setting the pointer that was passed, it is setting a local copy of the pointer since it was passed by value. You need to pass by reference in order to use the actual argument:
void fun(mystruct*& ptr);
Local variables are destroyed after the function returns. But even after you see a value inside the pointer that was set to a local variable, you can't assume that the local variable was not destroyed. If you dereference the pointer any time after assigning it to an expired object, your program then has Undefined Behavior.
Related: Can a local variable's memory be accessed outside its scope?
The code is pretty strange. For example in this function:
void fun(mystruct* ptr)
{
mystruct str = {10}; // create a structure
ptr = &str; // make ptr point to it
std::cout<<"bbq";
}
ptr is being set to something, but then it is never used. ptr is being passed by value so there is no way it can have an effect outside this function.
And here:
class cls
{
public:
mystruct* ptr;
void fun()
{
mystruct str = {10}; // create local variable
ptr = &str; // make ptr point to it
std::cout<<"bbq";
}
};
You are setting the class member ptr to point to a local variable, but then that variable is destroyed when the function returns, so ptr is left pointing to garbage. ptr isn't being used again in your example, so no harm done, but it is still strange.
And in your main:
int main()
{
mystruct* ptr = new mystruct; // make ptr point do a dynamically allocated object.
fun(ptr); // call fun with a copy of the pointer
std::cout<<"bbq";
cls obj;
obj.fun();
std::cout<<"bbq";
// That object that ptr is pointing to is never deleted.
}
There's no particular harm in not deleting something you allocated in this case, since
this is the end of your program, but it's good practice to delete your dynamically
allocated objects in general.
We could induce a failure by doing this:
struct mystruct
{
float x;
~mystruct() { x = 99; }
};
class cls
{
public:
mystruct* ptr;
void fun()
{
mystruct str = {10};
ptr = &str;
std::cout<<"bbq";
}
void fun2()
{
std::cout << ptr->x << std::endl;
}
};
...
obj.fun();
obj.fun2();
Now, it may happen that obj.fun2(); prints 99, or it may show some random other number, or it may crash. This is because the "use of an object that has been destroyed is undefined behaviour" - undefined behaviour means that the C++ standard does not define what happens, and "anything could happen", including crashing or hanging, or it works "as you expect". But the object will be destroyed. Since the original code doesn't actually USE ptr after the object it points to was destroyed, nothing bad happens (in fact, it's not even undefined behaviour in the example code - it is only undefined to "use pointed at object after the object has been destroyed").
Edit:
this code, however:
mystruct* ptr = new mystruct;
fun(ptr);
std::cout<<"bbq";
causes a memory leak, since ptr is never deleted (and if fun where to actually modify ptr outside of the function itself, e.g by using mystruct *&ptr as the argument, then you would have a memory block for mystruct that is no longer referenced, which is an even worse memory leak - and of course a value in ptr that points to destroyed object, so you can't use ptr anyway)
#include<iostream>
struct Test
{
int n ;
~Test(){}
Test& operator =(int v)
{
n=v;
return *this;
}
};
Test * ptr = nullptr;
void g(Test && p)
{
std::cout << "&&";
}
void g(Test & p)
{
ptr = &p;
std::cout << "&";
}
void f(Test&& t)
{
g(t);
}
void buggy()
{
*ptr = 5;
}
int main()
{
f(Test());
buggy();
std::cin.ignore();
}
Just to be sure, the above code lead to an undefined behavior as we keep address of a tempory ?
Declaring pointer to struct Test* ptr; or "keeping address" as you call it doesn't lead to an undefined behaviour. Using pointers to objects whose lifetime has ended does.
Lifetime of the object created by Test() in main ends right after f(Test()); is executed. After that, whatever you do by using ptr is undefined. This object most likely stays in the memory even after its lifetime has ended, but you shouldn't rely on it.
You should also check out: What are all the common undefined behaviours that a C++ programmer should know about?
Yes, the temporary Test() is allocated on the stack, you take a pointer to it and it's destructor is called after returning. After that, the value of the pointer is still valid, but it points to "undefined" memory so all bets are off on dereferencing the pointer.
I have read in C++ : The Complete Reference book the following
Even though objects are passed to functions by means of the normal
call-by-value parameter passing mechanism, which, in theory, protects
and insulates the calling argument, it is still possible for a side
effect to occur that may affect, or even damage, the object used as an
argument. For example, if an object used as an argument allocates
memory and frees that memory when it is destroyed, then its local copy
inside the function will free the same memory when its destructor is
called. This will leave the original object damaged and effectively
useless.
I do not really understand how the side effect occurs. Could anybody help me understand this with an example ?
Here is an example:
class bad_design
{
public:
bad_design( std::size_t size )
: _buffer( new char[ size ] )
{}
~bad_design()
{
delete[] _buffer;
}
private:
char* _buffer;
};
Note that the class has a constructor and a destructor to handle the _buffer resource. It would also need a proper copy-constructor and assignment operator, but is such a bad design that it wasn't added. The compiler will fill those with the default implementation, that just copies the pointer _buffer.
When calling a function:
void f( bad_design havoc ){ ... }
the copy constructor of bad_design is invoked, which will create a new object pointing to the same buffer than the one passed as an argument. As the function returns, the local copy destructor will be invoked which will delete the resources pointed by the variable used as an argument. Note that the same thing happens when doing any copy construction:
bad_design first( 512 );
bad_design error( first );
bad_design error_as_well = first;
That passage is probably talking about this situation:
class A {
int *p;
public:
A () : p(new int[100]) {}
// default copy constructor and assignment
~A() { delete[] p; }
};
Now A object is used as pass by value:
void bar(A copy)
{
// do something
// copy.~A() called which deallocates copy.p
}
void foo ()
{
A a; // a.p is allocated
bar(a); // a.p was shallow copied and deallocated at the end of 'bar()'
// again a.~A() is called and a.p is deallocated ... undefined behavior
}
Here is another example. The point is that when the callee (SomeFunc) parameter destructor is invoked it will free the same object (ptr) pointed to by the caller argument (obj1). Consequently, any use of the caller argument (obj1) after the invocation will produce a segfault.
#include <iostream>
using namespace std;
class Foo {
public:
int *ptr;
Foo (int i) {
ptr = new int(i);
}
~Foo() {
cout << "Destructor called.\n" << endl;
//delete ptr;
}
int PrintVal() {
cout << *ptr;
return *ptr;
}
};
void SomeFunc(Foo obj2) {
int x = obj2.PrintVal();
} // here obj2 destructor will be invoked and it will free the "ptr" pointer.
int main() {
Foo obj1 = 15;
SomeFunc(obj1);
// at this point the "ptr" pointer is already gone.
obj1.PrintVal();
}