I was preparing lecture on copy constructor and found this:
MyClass myFunction()
{
MyClass mc;
return mc;
}
the statement says:
If we call myFunction, then C++ will create a new myClass object
that's initialized to mc when myFunction returns. Thus while your code
might act like it's transparently moving the object from inside of
myFunction to the rest of your code, it's actually making a temporary
copy.
I think statement MyClass mc; will create the object and it returned form function not any temporary object.
Where am I going wrong? Can somebody elaborate the statement to be able to understand easily?
I think statement MyClass mc; will create the object
Correct.
and it returned form function not any temporary object.
I don't fully understand your statement, so I cannot tell whether you've gone wrong, but this is what happens:
mc is a local variable. Local variables are destroyed when the function exits. Before it is destroyed, a temporary object is copy-initialized from it. The temporary object is then returned from the function.
Extra knowledge 1: Since C++11, the temporary is copy-initialized by move, if possible.
Extra knowledge 2: Standard explicitly allows the compiler to skip the copy/move and instead construct the object at the call site. This optimization is known as (named) return value optimization and is a form of copy elision. Despite this, you can not return objects that are neither copyable nor movable. That is because an implementation of C++ is not required to do NRVO.
Let's say you have this code:
#include <iostream>
using namespace std;
class MyClass
{
public:
int *v;
MyClass()
{
v=new int[5];
for(int i=0;i<5;i++) v[i]=i; // x will look like : 0,1,2,3,4
}
~MyClass()
{
cout<<"Destructor called! Now v is deallocated! \n";
delete[] v;
}
};
MyClass myFunction()
{
MyClass mc;
return mc;
}
int main()
{
MyClass x;
x=myFunction();
cout<<x.v[2]<<'\n'; //it may or may not print the right thing
return 0;
}
As you can see, myFunction returns the object mc like you said. But you also know that the destructor of mc will be called when mc goes out of scope - mc is declared inside myFunction, so the destructor will be called after the function is executed and memory will be freed (delete[] v). The memory is deallocated, but the values are still there in the memory! So, even though x=myFunction(); will work, you will have an object where the memory v points to is deallocated! So, cout<<x.v[2]<<'\n'; may not print the right thing. If you compile the code it will probably print the correct value (2), because the memory was not overwritten, but if you would do some more allocations before the cout statement, or after some time of using your OS, you will see that the value printed is incorrect/crash as the memory will be overwritten by other programs. v still points to that memory block, but it doesn't know what's there because the memory is deallocated.
Inside myFunction: v -> |0|1| 2 |3|4|...
After exiting myFunction: v -> |0|1| 2 |3|4|.....
After some memory allocations: v -> |a|1| b |#|%|3|7|2|1|*|!|......
Related
Have looked at various similar questions here but still can't figure out why the following code does not compile:
// these three are defined somewhere
class A;
std::unique_ptr<A> make_a();
void take_a(std::unique_ptr<A>&&);
int main(){
take_a(make_a()); // this fails
return 0;
}
According to this:
If the default deleter is used, T must be complete at the point in
code where the deleter is invoked, which happens in the destructor,
move assignment operator, and reset member function of
std::unique_ptr.
As far as I understand, none of these (destructor, move assignment operator, nor reset member function) happens in main.
So why does compiler needs the definition of A here?
Since main has a unique_ptr within its scope, realistically it would need to know how to delete the object it holds.
It's possible that take_a doesn't actually take ownership of the object, thus main would need to delete.
main gets a temporary unique_ptr from make_a(), let's call it X. It then passes an rvalue reference to X to take_a. It still has the destroy X. Hence, it has to call the destructor after take_a, even though X would typically be empty at that point.
We need class A description (at least constructor and destructor) in order to create and move std::unique_ptr<A> objects; take_a(make_a()) is creating such object because make_a() is pass-by-value. It first creates a new unique_ptr<A> object, initialize it (using default constructor), and then update its value and returns this new object. Here the default constructor/destructor is being used, which the compiler is unable to find.
#include <bits/stdc++.h>
class A {
public: A() {}
public: ~A() {}
};
std::unique_ptr<A> make_a() {
std::cout << "make";
std::unique_ptr <A> tt = nullptr;
return tt;
}
void take_a(std::unique_ptr<A>&&) {
std::cout << "take";
}
int main(){
take_a(make_a()); // this works now
return 0;
}
Edit: Forgot to add the link. Works the other way too.
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.
I have class like this
class variable
{
public:
variable(int _type=0) : type(_type), value(NULL), on_pop(NULL)
{
}
virtual ~variable()
{
if (type)
{
std::cout << "Variable Deleted" <<std::endl;
on_pop(*this);
value=NULL;
}
}
int type;
void* value;
typedef void(*func1)(variable&);
func1 on_pop;
}
And then I push instances into a std::vector like this:
stack.push_back(variable(0));
I expect that the destructor of variable will be called but the if won't enter until a value is assigned to type because I expect the constructor I provide will be called when the instance is copied into the vector. But for some reason it is not.
After calling stack.push_back the destructor (of the copy?) is ran and type has some random value like if the constructor was never called.
I can't seem to figure what I am doing wrong. Please help! ^_^
EDIT:
Ok here is a self contained example to show what I mean:
#include <iostream>
#include <vector>
class variable
{
public:
variable(int _type=0) : type(_type), value(NULL), on_pop(NULL)
{
}
~variable()
{
if (type)
{
std::cout << "Variable Deleted" <<std::endl;
on_pop(*this);
value=NULL;
}
}
int type;
void* value;
typedef void(*func1)(variable&);
func1 on_pop;
};
static void pop_int(variable& var)
{
delete (int*)var.value;
}
static void push_int(variable& var)
{
var.type = 1;
var.value = new int;
var.on_pop = &pop_int;
}
typedef void(*func1)(variable&);
func1 push = &push_int;
int main()
{
std::vector<variable> stack;
stack.push_back(variable(0));
push(stack[stack.size()-1]);
stack.push_back(variable(0));
push(stack[stack.size()-1]);
stack.push_back(variable(0));
push(stack[stack.size()-1]);
return 0;
}
The program above outputs the following:
Variable Deleted
Variable Deleted
Variable Deleted
Variable Deleted
Variable Deleted
Variable Deleted
Process returned 0 (0x0) execution time : 0.602 s
Press any key to continue.
Welcome to RVO and NRVO. This basically means that the compiler can skip creating an object if it's redundant- even if it's constructor and destructor have side effects. You cannot depend on an object which is immediately copied or moved to actually exist.
Edit: The actual value in the vector cannot be ellided at all. Only the intermediate variable variable(0) can be ellided. The object in the vector must still be constructed and destructed as usual. These rules only apply to temporaries.
Edit: Why are you writing your own resource management class? You could simply use unique_ptr with a custom deleter. And your own RTTI?
Every object that was destructed must have been constructed. There is no rule in the Standard that violates this. RVO and NRVO only become problematic when you start, e.g., modifying globals in your constructors/destructors. Else, they have no impact on the correctness of the program. That's why they're Standard. You must be doing something else wrong.
Ultimately, I'm just not sure exactly WTF is happening to you and why it's not working or what "working" should be. Post an SSCCE.
Edit: In light of your SSCCE, then absolutely nothing is going wrong whatsoever. This is entirely expected behaviour. You have not respected the Rule of Three- that is, you destroy the resource in your destructor but make no efforts to ensure that you actually own the resource in question. Your compiler-generated copy constructor is blowing up your logic. You must read about the Rule of Three, copy and swap and similar idioms for resource handling in C++, and preferably, use a smart pointer which is already provided as Standard like unique_ptr which does not have these problems.
After all, you create six instances of variable- three temporaries on the stack, and three inside the vector. All of these have their destructors called. The problem is that you never considered the copy operation or what copying would do or what would happen to these temporaries (hint: they get destructed).
Consider the equal example of
int main()
{
variable v(0);
push_int(v);
variable v2 = v;
return 0;
}
Variable v is constructed and allocates a new int and everything is dandy. But wait- then we copy it into v2. The compiler-generated constructor copies all the bits over. Then both v2 and v are destroyed- but they both point to the same resource because they both hold the same pointer. Double delete abounds.
You must define copy (shared ownership - std::shared_ptr) or move (unique ownership - std::unique_ptr) semantics.
Edit: Just a quick note. I observe that you actually don't push into items until after they're already in the vector. However, the same effect is observed when the vector must resize when you add additional elements and the fundamental cause is the same.
The destructor is called 6 times. A constructor is called six times. Just not the one you intended.
Ok. I've been reading some more about the intrinsics of different containers and, apparently, the one that does the job I'm trying to accomplish here is std::deque.
Given the code :
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();
}
The output is :
Say i am in someFunc
Null pointer assignment(Run-time error)
I'm not able to understand why the second line of output comes. The second line of the output. I think that the compiler supplies a copy constructor when it is not explicitly specified. So, in the function SomeFunc(Sample x), the local object to SomeFunc() which is X of Sample type should be created and destroyed and the Sample type object (s1) in main() should remain intact and should be freed only after main exits. Please answer why the above behaviour is happening?
Why the above behaviour is happening??
Short Answer:
Because You are not following the Rule of Three.
Long Answer:
Your class has a pointer member ptr with dynamic memory allocation in constructor and deallocation in destructor while your code creates temporary copies of the object while passing to the function SomeFunc() by calling copy constructor, implicitly generated by the compiler, which creates a shallow copy of the pointer member. Once the temporary is destroyed at the end of function call the memory is deallocated in destructor and you are left with a dangling pointer.This invalid pointer is dereferenced further when you call the function PrintVal() resulting in a Undefined Behavior, which manifests in the form of a segmentation fault.
How to avoid this problem?
Short Answer:
Follow the Rule of Three.
Long Answer:
You should provide a copy constructor which creates a deep copy of the pointer member ptr. This ensures that the pointer member of the object created in member remains valid through out the lifetime of the program.
EDIT:
Actually, the problem might even occur even before the function gets called, specifically when you call:
Sample s1= 10;
This calls the conversion constructor,
Sample(int i)
to create a temporary Sample object which is then used for constructing s1 object by calling the implicit copy constructor, If this is the case the temporary object created will be destroyed after creation of s1 does leaving the pointer member ptr in a dangling state.
However, most of the compilers will apply optimizations through copy elision using Return Value Optimization(RVO) thus eliminating the need of calling the copy constructor & hence this might not be a problem.
In either case solution to the problem remains the same.
here is my c++ code :
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();
}
it returns me the output like :
Say i am in someFunc
Null pointer assignment(Run-time error)
here As the object is passed by value to SomeFunc the destructor of the object is called when the control returns from the function
should i right ? if yes then why it is happening ? and whats the solution for this ???
Sample is passed by value to SomeFunc, which means a copy is made. The copy has the same ptr, so when that copy is destroyed when SomeFunc returns, ptr is deleted for both objects. Then when you call PrintVal() in main you dereference this invalid pointer. This is undefined behavior. Even if that works then when s1 is destroyed ptr is deleted again, which is also UB.
Also, if the compiler fails to elide the copy in Sample s1= 10; then s1 won't even be valid to begin with, because when the temporary is destroyed the pointer will be deleted. Most compilers do avoid this copy though.
You need to either implement copying correctly or disallow copying. The default copy-ctor is not correct for this type. I would recommend either making this type a value type (which holds its members directly rather than by pointer) so that the default copy-ctor works, or use a smart pointer to hold the reference so that it can manage the by-reference resources for you and the default copy-ctor will still work.
One of the things I really like about C++ is that it's really friendly toward using value types everywhere, and if you need a reference type you can just wrap any value type up in a smart pointer. I think this is much nicer than other languages that have primitive types with value semantics but then user defined types have reference semantics by default.
You usually need to obey the Rule of Three since you have an pointer member.
In your code example to avoid the Undefined Behavior you are seeing:
Replace the need to in first statement by must.
Since SomeFunc() takes its argument by value, the Sample object that you pass to it is copied. When SomeFunc() returns, the temporary copy is destroyed.
Since Sample has no copy constructor defined, its compiler-generated copy constructor simply copies the pointer value, so both Sample instances point to the same int. When one Sample (the temporary copy) is destroyed, that int is deleted, and then when the second Sample (the original) is destroyed, it tries to delete the same int again. That's why your program crashes.
You can change SomeFunc() to take a reference instead, avoiding the temporary copy:
void someFunc(Sample const &x)
and/or you can define a copy constructor for Sample which allocates a new int rather than just copying the pointer to the existing one.
When you pass the argument for the function it's called the copy constructor, but you don't have one so the pointer is not initialised. When it exits the function, the object is calls the destructor to delete the unitialised pointer, so it thows an error.
Instead of
int main()
{
Sample s1= 10;
SomeFunc(s1);
s1.PrintVal();
}
try to use
int main()
{
Sample* s1= new Sample(10);
SomeFunc(*s1);
s1->PrintVal();
}