I am making some matrix class and I was wondering when a temporary object is created it is local to the function right? so it should get out of scope when function return but I don't know why that don't happen in this case I can use it after the function have returned.
Here is an example, this is the constructor:
int *data; //member of class
Matrix3(const int (&ar)[N*N])
{
data = const_cast<int*>(ar);
}
and here is how I use it:
Matrix3 m = { {1,2,3,4,5,6,6,6,6} };
Now I can still access that object from the destructor through the data pointer is this normal? the temporary variable is created on the heap then?!
The lifetime of a temporary ends at the semicolon of the statement or declaration that introduced it, not at the end of the function. (Otherwise, an innocuous loop could easily cause a stack overflow.)
If you use a reference to an object after its lifetime has ended (such as the array here), then you get undefined behavior. C++ does not keep track of dead objects in order to tell you when you are using one. You happen to find the information from the dead array. But something else could have reused the memory, or it could have been returned to the system and you could get a segfault.
Avoid dangling references and pointers. Do not suppose that if it works in a test-case, that it works in the field.
After your line executes, the temporary array is destroyed and the data pointer becomes invalid.
int *data; // is a member, so it goes out of scope when the object is destroyed
However, if you declared it in a function like this:
void someFunction() {
int *data;
}
// pointer is lost now and is inaccessible
Related
So I was writing a piece of code where I used new operator to create an object inside a local scope function and returned the reference as a pointer.
A* operator+(A that){
int sumA = a + that.getA();
int sumB = b + that.getB();
return new A(sumA, sumB);
}
In my thought It would not work because the object was created inside the local scope and should be temporary, but it compiled and ran. Can anyone explain to me about this? I am sure there are other things that kinda have the ability of breaking the scope and stuff.. If possible, could you give me some examples? Appreciated!
When you say "created inside local scope" what you really mean is "an automatic variable." Automatic variables are automatically destroyed when the scope in which they are created is exited from.
But new does not create an automatic variable. It creates a dynamically allocated object, whose lifetime is not bound by the scope in which it's created.
The object created by, new A(sumA, sumB) is not a temporary.
Values are returned from a local scope all the time. For example:
int f(int x)
{
int y = x*x;
return y;
}
While a variable would normally disappear when it falls out of scope, values returned from functions get special treatment by the compiler.
Regarding your example, you are creating an object on the heap and have a pointer to that object on the local stack. When your function returns the stack is cleaned up, that pointer along with it. Except - since you're returning the pointer to the caller, a copy of the pointer is passed back to the caller (probably through a cpu register).
As an aside: While this works fine, you need to be certain that the caller eventually deletes the returned object, else you'll have a memory leak.
C++ does not automatically manage memory for you. This means you must manually 'delete' any objects created dynamically with the 'new' operator. Your code is valid, but I think it doesn't accomplish what you wish. I think you are looking for something like this:
A operator+(const A& that){
int sumA = a + that.getA();
int sumB = b + that.getB();
return A(sumA, sumB);
}
Yes, the value created with new will still be alive after the function exits.
As others have mentioned, it is necessary to delete these objects to avoid memory leaks.
Because of this, best general C++ practice is to not return bare pointers like this function does, but to return some sort of smart pointer object such as shared_ptr. That way, you can return a pointer to the newly created object, and the object will be automatically destroyed once there are no more active references to it.
I'm trying to figure out why the following code breaks. After objects->pop(); is called in the lambda expression, the memory address of objects changes to 0xfeeefeee when debugging in Visual Studio. I can get around this issue by doing auto p = objects; before the pop, and then using p instead of objects in the second line of the lambda. However, I must be missing something fundamental here.
class Obj
{
public:
Obj(stack<shared_ptr<Obj>>* const objects) {
fun = [=] {
objects->pop(); // objects' address changed after this executes
objects->push(shared_ptr<Obj>(new Obj(objects)));
};
}
function<void(void)> fun;
};
int main()
{
stack<shared_ptr<Obj>> objects;
objects.push(shared_ptr<Obj>(new Obj(&objects)));
objects.top().get()->fun();
return 0;
}
What you are observing is undefined behavior.
The memory that the captured objects variable occupies is freed when you call objects->pop(); A good hint for this is the value it changes to: 0xFEEEFEEE. This magic number indicates freed memory.
Let's analyse what happens.
stack<shared_ptr<Obj>> objects;
objects.push(shared_ptr<Obj>(new Obj(&objects)));
A stack with shared_ptr's is created. Pushed on top of it is a new Obj instance, whose constructor argument is a pointer to our stack.
Obj(stack<shared_ptr<Obj>>* const objects) {
fun = [=] {
/* ... */
};
}
A function object is assigned a lambda, which captures the objects argument.
objects.top().get()->fun(); calls the function object:
objects->pop(); // objects' address changed after this executes
The top element of the stack that objects points to, is the Obj instance to which the fun object belongs. By popping it off, the only (and therefore last) instance of the shared_ptr holding a reference to it goes out of scope and frees the memory that it used. This includes the captured pointer to objects. In a debug build HeapFree sets it to 0xFEEEFEEE. In a release build anything could happen. After this point you're referencing released memory, which is undefined behavior.
When you call objeccts->pop(), the shared_ptr on top of the stack is destroyed. It is the last pointer to your instance of Obj, so that instance is destroyed. That instance contains the function object fun, so the function object is also destroyed.
Any access to the captured variables of the function object after this point is undefined behaviour, which first happens right on the next line.
For what I could deduce debugging your code, it seems to me that eventually you are doing pop on the top of stack, and with that you are trying to delete the pointer to the objects (the variable in the main function: by the way, you should rename that to eliminate confusion). As it is not on the heap, UB kicks in, and it gives (me) a segmentation fault.
In the following code:
class Array {
public:
int& operator[] (unsigned i) { if (i > 99) error(); return data[i]; }
private:
int data[100];
};
int main()
{
Array a;
a[10] = 42;
a[12] += a[13];
...
}
(Correct me if I'm wrong) The variable a of type Array is on the stack since new was not used to allocate it. The Array class has int data[100], and the operator overload returns reference to particular index in data.
Referring question.
My question is whether int data[100] is on the stack or heap ? I think it shouldn't be the stack, otherwise how can a reference return like the one above still work.
Thanks.
It's on the stack, since as you've noted a was allocated on the stack.
The stack is memory just like the heap; you can return a reference to part of it just like memory allocated on the heap. The only difference is in how the memory is managed.
The only thing you need to be careful of is not to access memory that's been deallocated; in the case of the stack, this happens at the end of a's scope, while heap-allocated data has to be explicitly deleted.
In the question you refer to, a reference to a variable declared on the stack is returned from a function; in that case, the variable is destroyed when the function exits, which is why that code is wrong. In your case, however, you're returning a reference to part of data whose lifetime matches that of the Array object; so as long as a has not been destroyed, it's safe to access it's data in this manner.
As you say, "The variable a of type Array is on the stack". Technically, the object named a is on the stack. This means that all of the member variables of the object a are on the stack.
This means that return a reference to an element in the member array named data is very dangerous. The compiler will allow it, but if you try to access this reference when the variable a is out of scope, then you will encounter undefined behavior.
In the case of your example, all calls to operator[]() are within the same method, so everything is fine.
It's on the stack. Why would the reference return be a problem? You can create and use references to things on the stack without a problem.
void foo(void)
{
int i;
int& j = i; // reference to variable on the stack
j = 2;
}
What issue do you think there might be here?
My question is whether int data[100] is on the stack or heap ? I think it shouldn't be the stack, otherwise how can a reference return like the one above still work.
It is allocated with automatic storage duration, i.e., the stack, not the heap. You have not allocated anything dynamically, so no dynamic (heap) allocation occurs. That would be a horrible thing to allow and C++ is all about not paying for what you don't use.
A reference to an element of data or to data itself will be invalid if data has left its declaring scope, i.e., the scope of the instance of Array. Now, should an Array type use dynamic allocation? Almost certainly, yes, for a general purpose container. It's your responsibility to make sure you're not keeping references or pointers to bad data.
It will be on the stack. If you try to use that reference after "a" has gone out of scope, you will get undefined behaviour. Hopefully it will crash soon.
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();
}
I am starting again with c++ and was thinking about the scope of variables.
If I have a variable inside a function and then I return that variable will the variable not be "dead" when it's returned because the scope it was in has ended?
I have tried this with a function returning a string and it did work.
Can anyone explain this? Or at least point me to some place that can explain this to me please.
Thanks
When the function terminates, the
following steps happen:
The function’s return value is
copied into the placeholder that was
put on the stack for this purpose.
Everything after the stack frame
pointer is popped off. This destroys
all local variables and arguments.
The return value is popped off the
stack and is assigned as the value
of the function. If the value of the
function isn’t assigned to anything,
no assignment takes place, and the
value is lost.
The address of the next instruction
to execute is popped off the stack,
and the CPU resumes execution at
that instruction.
The stack and the heap
When you return a value, a copy is made. The scope of the local variable ends, but a copy is made, and returned to the calling function. Example:
int funcB() {
int j = 12;
return j;
}
void A() {
int i;
i = funcB();
}
The value of j (12) is copied and returned to i so that i will receive the value of 12.
It really depends on what kind of variable you are returning. If you return a primitive then it is returned by copy, not by reference so the value is copied to the top of the stack (or, more often placed into a register) where the calling function can get it. If you allocate an object or memory on the heap and return a pointer then it doesn't die because it's on the heap, not the stack. If you allocate something on the stack, however, and return it, that would be a bad thing. For instance, either of these would be very bad:
int *myBadAddingFunction(int a, int b)
{
int result;
result = a + b;
return &result; // this is very bad and the result is undefined
}
char *myOtherBadFunction()
{
char myString[256];
strcpy(myString, "This is my string!");
return myString; // also allocated on the stack, also bad
}
Just for a little bit more of a memory-model oriented explanation: when a function is called, a temporary space is made for the function to put its local variables, called a frame. When the function (callee) returns its value, it puts the return value in the frame of the function that called it (caller), and then the callee frame is destroyed.
The "frame is destroyed" part is why you can't return pointers or references to local variables from functions. A pointer is effectively a memory location, so returning the memory location of a local variable (by definition: a variable within the frame) becomes incorrect once the frame is destroyed. Since the callee frame is destroyed as soon as it returns its value, any pointer or reference to a local variable is immediately incorrect.
This depends on the type of the returned item. If you are returning by value, a new copy of the variable is made to return to the caller. I thins case you do not need to worry about object lifetime, but you may need to worry about the costs of copying objects (but please don't prematurely optimze - correctness is much more important):
std::string someFunc( std::string& const s)
{
return s + "copy";
}
If the function is returning a reference, then you need to be careful about what you're returning because it's lifetime needs to extend beyond the function's lifetime and the caller will not necessarily be able todelete it if you're using new to create the object:
std::string& someFunc2( std::string const& s)
{
return s + "reference to a copy"; // this is bad - the temp object created will
// be destroyed after the expression the
// function call is in finishes.
// Some, but not all, compilers will warn
// about this.
}
Of course, returning pointers will have similar lifetime considerations.
The local variable is copied to the return value. Copy constructors are called for non-trivial classes.
If you return a pointer or reference to a local variable you will have trouble---just as your intuition suggested.