This question already has answers here:
What is The Rule of Three?
(8 answers)
Closed 8 years ago.
I am preparing for a C++ test and came across this code example.
In the code example below, obj is passed to SomeFunc. SomeFunc has parameter Foo obj so a copy is made which results in a Foo being created and later destroyed when SomeFunc function returns.
If you change the function signature to:
SomeFunc(Foo& obj);
or better:
SomeFunc(const Foo& obj);
problem goes away.
What is puzzling however is why the code crashes on the obj.PrintVal(); line.
I can understand how on calling SomeFunc that a new Foo is created and destroyed when the function returns, but I thought that would be isolated to the local copy of obj in SomeFunc. But when I step through in my debugger I find that the ptr of obj in main is deallocated. and so on calling obj.PrintVal() - the dereference of ptr causes segmentation fault / access violation.
Can someone please explain what is happening.
#include <iostream>
class Foo
{
public:
int *ptr;
Foo(int i) {
ptr = new int(i);
}
~Foo() {
delete ptr;
}
int PrintVal() {
std::cout << *ptr;
return *ptr;
}
};
void SomeFunc(Foo obj) {
int x = obj.PrintVal();
}
int main() {
{
Foo obj= 15;
SomeFunc(obj);
obj.PrintVal();
}
return 0;
}
It's "crashing" because you have made a copy of that pointer unintentionally, and the delete is called on an already deleted pointer.
You need to provide a copy constructor (different from the automatically created one), that does handle this correctly (create a new pointer for the copy).
Related
This question already has answers here:
What will happen when I call a member function on a NULL object pointer? [duplicate]
(6 answers)
Closed 5 years ago.
I've written a very simple code. In created an object dynamically, and then I delete that object and assign it to zero. After that I access a member function of that object, but my program does not crash, instead it returns value.
class MyClass
{
public:
MyClass() {}
int funct() { return 0; }
};
int main()
{
MyClass *mc = new MyClass;
delete mc;
mc = 0;
// The program should crash here as I've set mc to zero after deleting
// it. But it returns the value.
int retVal = mc->funct();
return 0;
}
As per my understanding with new, delete and assignment to zero, this code should crash, or give exception.
You can visualize your method as a function:
int funct(MyClass *this) { return 0; }
You can see that the function doesn't use this at all so it won't crash if it is 0.
However, don't do such things in real code. This is still an Undefined Behavior and compiler optimizations can mess it up.
Below is the code which has various return statements and all are working perfectly fine.
Compiler throws the warning for fun_ret_obj1
Test.cpp: In function ‘myClass& fun_ret_obj1()’:
Test.cpp:45: warning: reference to local variable ‘myObj’ returned
But still the output seems to be fine.Is it by Chance?
Are there any catches with any of the return statements below?
Explanation would be really helpful, Thanks
#include <iostream>
using namespace std;
class myClass {
public:
int a ;
myClass()
{
a = 10;
}
};
myClass& fun_ret_add()
{
myClass *ptr = new myClass();
return *ptr;
}
myClass* fun_ret_ptr()
{
myClass *ptr = new myClass();
return ptr ;
}
myClass fun_ret_obj()
{
myClass myObj;
return myObj;
}
myClass& fun_ret_obj1()
{
myClass myObj;
return myObj;
}
int main()
{
myClass obj,obj1;
std::cout <<"In Main \n";
myClass *a = fun_ret_ptr();
std::cout<<a->a<<"\n";
myClass &b = fun_ret_add();
std::cout<<b.a<<"\n";
myClass c = fun_ret_obj();
std::cout<<c.a<<"\n";
myClass d = fun_ret_obj1();
std::cout<<d.a<<"\n";
}
First one is a memory leak:
myClass& fun_ret_add()
{
myClass *ptr = new myClass();
return *ptr;
}
Second one returns a raw pointer (evil - return a std::unique_ptr)
myClass* fun_ret_ptr()
{
myClass *ptr = new myClass();
return ptr ;
}
Third one is perfect - returns a copy, which will almost always be elided. In c++17 it's guaranteed to be elided. This is efficient and safe.
myClass fun_ret_obj()
{
myClass myObj;
return myObj;
}
update
In c++17 you could guarantee the elision of the copy this way:
myClass fun_ret_obj()
{
return myClass{};
}
end of update
Fourth one is undefined behaviour. Returning a reference to a non-existent object. Never do this.
myClass& fun_ret_obj1()
{
myClass myObj;
return myObj;
}
regarding memory leaks
It is true that in the first example, a caller could release the memory if he/she knew that myClass had been allocated with new:
auto& x = fun_ret_add(); // a
...
delete std::addressof(x); // b
This would require:
That the caller knows that fun_ret_add() is implemented in terms of new.
That the implementation of fun_ret_add() never changes
That no exceptions occur between (a) and (b)
The second example is similar. In this case, at least there is a hint that the object needs to be deleted, but the caller must still know that the object has been allocated with new, and he must guard against exceptions.
Contrast with this:
std::unique_ptr<myClass> fun_ret_ptr()
{
return std::make_unique<myClass>();
// or
return { new myClass() };
// or
return std::unique_ptr<myClass>(new myClass());
}
Now the caller receives a smart pointer. If the caller does nothing but use this pointer, the myClass object will be properly deleted when the pointer goes out of scope, and all memory will be reclaimed.
myClass& fun_ret_obj1()
{
myClass myObj;
return myObj;
}
This creates a local variable on the stack, myObj. And returns a reference to that object. Then the object is destroyed because of it's scope. The moment the caller sees the reference it's referencing a stack object that has been destroyed, using it is undefined behaviour. And thus your compiler warns you about that.
OK some explanations:
myClass fun_ret_obj()
{
myClass myObj;
return myObj;
}
This one simply calls a copy-constructor. Nothing really special here.
myClass* fun_ret_ptr()
{
myClass *ptr = new myClass();
return ptr ;
}
This one returns a pointer to a heap allocated object. It will never be deleted until you manually delete it. But it's safe to return.
myClass& fun_ret_add()
{
myClass *ptr = new myClass();
return *ptr;
}
This one will return a reference to the value. While this is OK. You can not access the pointer ptr anymore and thus not delete the object manually. (OK you still could delete the object but you have to know later that this object was initially created on the heap and not on the stack to not cause any strange errors elsewhere. So this is likely to not get deleted later)
myClass& fun_ret_obj1()
{
myClass myObj;
return myObj;
}
This one is critical. The moment the function goes out of scope the destructor will be called. (if you set a to a invalid value in the destructor you will see this).
Because the computer is "smart" and just says "this memory can be overwritten when needed" it gets not "deleted" (the destructor gets called though just not the memory location invalidated). So directly accessing the memory afterwards results in what seems like valid behavior. But this is just by accident. When you would initialize some variables or have some memory allocations on the stack this would get overwritten and you access strange memory. That's why this is undefined behavior and the compiler warns you here.
It's by chance. Your compiler doesn't lie.
Here:
myClass& fun_ret_obj1() {
myClass myObj;
return myObj;
}
You are returning a reference to an object that is going to be destroyed.
You are going to face what is called undefined behavior, it could either works or not.
In your case:
the output seems to be fine
And it's by chance, of course.
myClass fun_ret_obj()
{
myClass myObj;
return myObj;
}
Looks innocent enough, but under the hood will create two temporaries (invoking the ctor on each, which propagates to ctors of all member objects, and so on...). Then when returning will copy the first temporary to the other before deleting it (invokes its dtor and the dtor of all member objects, and so on...), will then invoke the copy ctor (or assignment operator and those of its member objects, and so on...) for the receiving object in the caller, then delete the second temporary (invoking the dtor and the dtor of all member objects, etc...). Even if myClass and of its all member objects have implemented move semantics this may actually be a very heavy duty operation. Better to pass a reference parameter to the receiving object and perhaps use a POD sentinel (success/fail) as the function return type, or use std::unique_ptr as described perfectly by Richard.
This question already has answers here:
Accessing class members on a NULL pointer
(8 answers)
Closed 6 years ago.
I do not understand how the below piece of code yields the given output.
#include <iostream>
using namespace std;
class MyClass
{
public:
void doSomething()
{
cout<<"Inside doSomething"<<endl;
}
};
int main()
{
MyClass obj;
MyClass *ptr=&obj;
ptr->doSomething();
ptr=NULL;
ptr->doSomething();
}
Output
Inside doSomething
Inside doSomething
I executed a function with a null pointer and it actually calls the function.
Retrieving the address stored in the ptr using cout of ptr shows that ptr is set to 0 after the statement ptr=NULL; .But it still calls doSomething().What is actually happening inside ?
This is Undefined Behaviour, and absolutely anything could happen, including appearing to work. This is not reliable!!
In this case, it doesn't crash, simply because the MyClass::doSomething() function doesn't do anything with its this pointer (which would be NULL, so likely to cause a crash).
If you gave MyClass a member, and attempted to access that in doSomething(), I'd expect to see a crash (segfault):
class MyClass
{
int someNum;
public:
void doSomething()
{
cout<< "Inside doSomething: " << this->someNum <<endl;
}
};
(And in my test with gcc 4.9.2. on Linux, I do indeed see a segfault.)
Also, please reconsider your use of bad practices using namespace std; and endl.
The reason is that you only access the code segment of the class which is always there.
But the moment you try to access any member variable from within the function you most likely will crash.
So, there is a hidden this pointer passed for every function, So after deleting the object this pointer is invalid.. So any access to this pointer will crash after the object was deleted.
Here is simplified version of what is happening internally:
doSomething(MyClass * this)
{
// Will work OK if 'this' pointer is NULL, but NOT used.
// Will Crash if 'this' pointer is used.
this->data = 100;
}
This question already has answers here:
What is The Rule of Three?
(8 answers)
Closed 8 years ago.
i have a little program that tries to do it but fails
class myclass{
public:
int * ptr;
myclass (){
ptr = new int;
}
myclass (const myclass &class_inst){
ptr = new int;
*ptr = *class_inst.ptr;
}
~myclass (){
delete ptr;
}
};
myclass dosomething (myclass a){
// make some changes to a
return a;
}
int main(){
myclass test1;
test1 = dosomething (test1);
return 0;
}
after test1 = dosomething.. is executed, test1's destructor is called. it gets called again at the end of main and that causes a seg fault.
1 way to fix this would be to have dosomething as a member function and use test1.dosomething(). Id like to know what is wrong with the above code.
Thanks!
You allocate memory for the single int, store the pointer to it to ptr, and then overwrite the same pointer with class_inst's pointer. When destructed both objects try to deallocate the same memory block.
I assume you wanted to copy the contents.
myclass (const myclass &class_inst){
ptr = new int;
*ptr = *class_inst.ptr;
}
Echoing Mooing Duck's comment about the rule of three, I will try and walk through what happens at each step of your main (apologies for any mangled indentation):
int main(){
myclass test1; //myclass default ctor called.
//ptr assigned a new int (uninitialised)
test1 = dosomething (test1); //make a copy of test1
//a.ptr is assigned a new int and then assigned class_inst.ptr, losing the original “new int” which will be leaked
//return a copy (call it result) constructed my class of argument a (which is a copy of test 1)
//result.ptr is assigned a new int and then assigned class_inst.ptr,
//losing the original “new int” which will be leaked
//a goes out of scope, and calls its door which deletes it’s a.ptr, which is pointed to by result.ptr (which in turn is class_inst.ptr)
return 0; //test1 (which is the same as result above) goes out of scope and tries to delete its ptr member, which is != NULL
//and then you get the seg fault
}
So what you should do is look up the rule of three (aka the big three), think about what happens in the default and copy constructors really hard, and equally so about the destructor.
So I'm curious of the reason the following code crashes.
Will appreciate help.
#include <iostream>
using namespace std;
class temp
{
public:
temp(int i)
{
intPtr = new int(i);
}
~temp()
{
delete intPtr;
}
private:
int* intPtr;
};
void f (temp fInput)
{
cout << "f called" << endl;
}
int main()
{
temp x = 2;
f(x);
return 0;
}
You are violating The Rule of Three
You maintain a pointer member and you pass a copy of the object to the function f. So, the end result is that you call delete twice on the same pointer.
The crash occurs because of the way you are passing x.
After the scope of the f function, x's destructure will be called and will delete intPtr.
However, that will delete memory that is still in scope for main. Therefor, after return 0 is called, it will try to delete memory that already exists as you are calling delete twice on the same pointer.
To fix this error, change
void f (temp fInput)
to
void f (const temp& fInput)
Alternatively, you could look into using a std::shared_ptr.
The pointer is copied when x is passed (implicit copy constructor) and the destructor is called twice (before the function returns and before main returns), thus the memory is deleted twice.
Use std::shared_ptr<int> here instead instead of a raw int pointer (assuming you want the behavior to be the same, i.e. reference the same int from both temps; otherwise, implement the copy constructor, move constructor and assignment operator yourself).
#include <memory>
class temp {
public:
temp(int i) : intPtr(std::make_shared<int>(i)) {
}
private:
std::shared_ptr<int> intPtr; // reference counting ftw
};
The problem you're hitting here is a double delete. Because you didn't define any copy constructors here C++ is happily doing so for you. The implementation does this by performing a shallow copy of all of the contents.
f(x);
This line works by creating a copy of x and passing it to f. At this point there are 2 temp instances which own a single intPtr member. Both instances will delete that pointer and this is likely what is causing your crash.
To work around this you can take a number of steps
Use a pointer type meant for sharing like shared_ptr<T>
Create an uncallable copy constructor which forces the instance to be passed by ref
An example of #2 is
class temp {
temp(const temp& other);
temp& operator=(const temp& other);
public:
// Same
};
Now the f(x) line simply won't compile because it can't access the necessary copy constructor. It forces it to instead redefine f to prevent a copy.
void f(const temp& fInput) {
...
}