• Memory being lost?
    15 replies, posted
Hello, I've been re-reading on pointers and things like that. And I made a test program that causes what I think is memory lossage. Only problem, is that I'm not exactly sure how it gets lost. Here's what I made: [code] //TestClassTwo.h #pragma once class TestClass2 { public: TestClass2() { Integer = 0; } int Integer; private: }; [/code] [code] //TestClass3.h #include "TestClassTwo.h" #include <iostream> class TestClass3 { public: TestClass3(){} void SetClass(TestClass2 Class) { Integer = &Class.Integer; } int *Integer; private: }; [/code] [code] //main.cpp #include "TestClassTwo.h" #include "TestClass3.h" #include <iostream> #include <vector> int main() { std::vector <TestClass3> Classes; TestClass2 TC2; TestClass3 TC3; TC2.Integer = 20; TC3.SetClass(TC2); Classes.push_back(TC3); std::cout<<*Classes[0].Integer<<"\n"; } [/code] This is just a program that I made so I could quickly learn things. But I just can't grasp how the memory gets lost. So I was hoping that someone could explain what points it gets lost, and more importantly how. But of course, thanks in advanced, it means a lot. Sorry if it's obvious, I'm not too well with how exactly memory works. I'm just the kind of person that needs to know how things work, because I can't stand something working "out of luck", I need to know why it worked.
You assign the value 20 to a pointer. This ends up in undefined behavior if you try to dereference it, since the address 20 is unlikely to be in your program space. [b]EDIT:[/b] Ignore my post, i did not read the OP's code properly.
The most common form of memory "loss" is a memory leak, which is where you allocate memory on the heap, and then destroy the pointer to it, effectively removing the ability to deallocate it. I don't see anything in your code that would cause this, although I do see a possible problem. In TestClass3::SetClass(), you return a pointer to a function argument. The function argument is a copy of the TS2 object and exits scope when the function ends, so that could cause problems. You should use a pointer or reference to the actual object. [QUOTE=florian;20982993]You assign the value 20 to a pointer. This ends up in undefined behavior if you try to dereference it, since the address 20 is unlikely to be in your program space.[/QUOTE] TestClass2::Integer isn't a pointer. [editline]*[/editline] Oh wait, that isn't returning, that's assigning. Working on something at the same time and read it as: [cpp] void *SetClass(TestClass2 Class) { return &Class.Integer; } [/cpp] Durr. Point still stands though.
[QUOTE=-SC-Lakitu;20983084]I don't see anything in your code that would cause this, although I do see a possible problem. In TestClass3::SetClass(), you return a pointer to a function argument. The function argument is a copy of the TS2 object and exits scope when the function ends, so that could cause problems. You should use a pointer or reference to the actual object.[/QUOTE] This is correct (aside from the bit about "return"), but stated more clearly: in TestClass3::SetClass() you're taking the address of part of a [i]temporary copy[/i] of TC2 that exists only while SetClass() is running. Once SetClass() finishes, that place in memory no longer contains a valid object, but you still have a pointer pointing to it. When you dereference it later, on the std::cout line in main(), you get "undefined behavior" -- likely either a crash or a garbage value.
Thank you all. It's all making sense now. I didn't know that when you have a function the doesn't take a reference of something it creates one and terminates it at the of the function. Which explains it all. Thank you. =D
Parameters that are passed by value (that is, not passed by reference) are copied into the called function's stack frame. Those copies are destroyed when the function returns. Objects are typically passed by reference (usually const reference, unless the function actually needs to modify the object) to avoid the overhead of making a copy every time the function is called. Since objects may be large, and may have copy constructors and destructors that have to be called, copying them frequently is inefficient.
Okay, at first I understood this, and I still do. But this is throwing me off: [code] #include <iostream> class TestClass2 { public: TestClass2() { Integer = 123; } int Integer; private: }; class TestClass3 { public: TestClass3(){} void SetClass(TestClass2 Class) { Integer = &Class.Integer; } int *Integer; private: }; int main() { TestClass2 TC; TestClass3 TC1; TC1.SetClass(TC); std::cout<<*TC1.Integer; } [/code] Why does it output 123 (the correct number)? Wouldn't it be a messed up number since in the SetClass() function it doesn't take a reference, making that object destroyed at the end?
[QUOTE=xAustechx;21009943]Okay, at first I understood this, and I still do. But this is throwing me off: [code] #include <iostream> class TestClass2 { public: TestClass2() { Integer = 123; } int Integer; private: }; class TestClass3 { public: TestClass3(){} void SetClass(TestClass2 Class) { Integer = &Class.Integer; } int *Integer; private: }; int main() { TestClass2 TC; TestClass3 TC1; TC1.SetClass(TC); std::cout<<*TC1.Integer; } [/code]Why does it output 123 (the correct number)? Wouldn't it be a messed up number since in the SetClass() function it doesn't take a reference, making that object destroyed at the end?[/QUOTE]I'm going to guess that the variable isn't destroyed and is still in the program's memory. When the variable goes out of scope, it is not actually immediately destroyed in the sense that the value is deleted. Local variables are stored in the stack. The stack pointer (a register in the CPU pointing to the start of the stack) is changed at the start of the function to accommodate for the local variables, and is reset at the end of the function. Thus, *TC1.Integer is not technically on the stack according to the stack pointer, but the value still exists and is preserved since the stack memory is not touched again until after std::cout()'s << operator is executed. Taking an educated guess here, I could be wrong. [editline]*[/editline] I did a little test to show this happening: [cpp] #include <iostream> class TestClass2 { public: TestClass2() { Integer = 123; } int Integer; private: }; class TestClass3 { public: TestClass3(){} void SetClass(TestClass2 Class) { Integer = &Class.Integer; } int *Integer; private: }; int main() { TestClass2 TC; TestClass3 TC1, TC2; TC1.SetClass(TC); TC.Integer = 183; TC2.SetClass(TC); std::cout<<*TC1.Integer; } [/cpp] When compiled and run, the output is: [code] 183 [/code]
[QUOTE=-SC-Lakitu;21010625]I'm going to guess that the variable isn't destroyed and is still in the program's memory. When the variable goes out of scope, it is not actually immediately destroyed in the sense that the value is deleted. Local variables are stored in the stack. The stack pointer (a register in the CPU pointing to the start of the stack) is changed at the start of the function to accommodate for the local variables, and is reset at the end of the function. Thus, it does not exist on the stack, but is preserved in memory since the stack is not touched until after std::cout()'s << operator is executed. Taking an educated guess here, I could be wrong. [editline]*[/editline] I did a little test to show this happening: [cpp] #include <iostream> class TestClass2 { public: TestClass2() { Integer = 123; } int Integer; private: }; class TestClass3 { public: TestClass3(){} void SetClass(TestClass2 Class) { Integer = &Class.Integer; } int *Integer; private: }; int main() { TestClass2 TC; TestClass3 TC1, TC2; TC1.SetClass(TC); TC.Integer = 183; TC2.SetClass(TC); std::cout<<*TC1.Integer; } [/cpp] When compiled and run, the output is: [code] 183 [/code][/QUOTE] I was reading up on stacks and heaps. And it was talking about how stacks are special and they basically have the ability to only let it use the latest variable passed, and if another is passed it will knock off the latest one. So does this mean that every function has a stack of it's own? -Edit Never mind, I'm sorry. I misread the reading a bit. I think I understand it.
[QUOTE=xAustechx;21009943]Okay, at first I understood this, and I still do. But this is throwing me off: -snip- Why does it output 123 (the correct number)? Wouldn't it be a messed up number since in the SetClass() function it doesn't take a reference, making that object destroyed at the end?[/QUOTE] Move TC to the heap instead of stack, and it probably will give you an access violation (after deleting TC, of course). Currently 'undefined behaviour' occurs, which is just that; in many cases undefined behaviour can do the right thing under the right circumstances. In this case, the stack memory used for TC simply hasn't been used by anything else yet.
[QUOTE=xAustechx;21010822]I was reading up on stacks and heaps. And it was talking about how stacks are special and they basically have the ability to only let it use the latest variable passed, and if another is passed it will knock off the latest one. So does this mean that every function has a stack of it's own?[/QUOTE]Kind of. The stack looks like this. [IMG]http://wpcontent.answers.com/wikipedia/en/thumb/a/a7/ProgramCallStack2.png/350px-ProgramCallStack2.png[/IMG] Assume N is TC.SetClass()'s frame, N-1 is main()'s frame, and address 11 is TC.Integer. Before calling TC.SetClass(TC1), the stack pointer is 17, and as far as the program is concerned TC.SetClass()'s stack space is not used. When TC.SetClass(TC1) starts, the stack pointer is set to 9 to accommodate for the local variables of TC.SetClass(). TC1.Integer is set to 11, as this is where TC.Integer is currently. When SetClass(TC1) ends, the stack pointer is set to 17 as the variables are no longer in scope. The variable is not actually deleted, the stack pointer is just changed, and the stack space the variable existed in is now considered free memory. When another function uses the same stack space it will be overwritten, which is where "undefined behavior" occurs after you dereference TC1.Integer.
[QUOTE=-SC-Lakitu;21011030]Kind of. The stack looks like this. [IMG]http://wpcontent.answers.com/wikipedia/en/thumb/a/a7/ProgramCallStack2.png/350px-ProgramCallStack2.png[/IMG] Assume N is TC.SetClass()'s frame, N-1 is main()'s frame, and address 11 is TC.Integer. Before calling TC.SetClass(TC1), the stack pointer is 17, and as far as the program is concerned TC.SetClass()'s stack space is not used. When TC.SetClass(TC1) starts, the stack pointer is set to 9 to accommodate for the local variables of TC.SetClass(). TC1.Integer is set to 11, as this is where TC.Integer is currently. When SetClass(TC1) ends, the stack pointer is set to 17 as the variables are no longer in scope. The variable is not actually deleted, the stack pointer is just changed, and the stack space the variable existed in is now considered free memory. When another function uses the same stack space it will be overwritten, which is where "undefined behavior" occurs after you dereference TC1.Integer.[/QUOTE] Sorry for the bump, but one (most likely last) question. [code] #include <iostream> class TestClass { public: TestClass(){} void Foo() { int TestNum = 1021; Integer = &TestNum; } int *Integer; private: }; void AddToStack(int Num) { } int main() { TestClass TC; TC.Foo(); AddToStack(10); std::cout<<*TC.Integer<<"\n"; } [/code] Why does *TC.Integer output as a garbage value and not 10? Isn't TestNum added on the stack, and is "replaced" by 10? Also, how come it's garbage when AddToStack() is called, but is outputted 1021 when not?
[QUOTE=xAustechx;21049950]Sorry for the bump, but one (most likely last) question. [code] #include <iostream> class TestClass { public: TestClass(){} void Foo() { int TestNum = 1021; Integer = &TestNum; } int *Integer; private: }; void AddToStack(int Num) { } int main() { TestClass TC; TC.Foo(); AddToStack(10); std::cout<<*TC.Integer<<"\n"; } [/code]Why does *TC.Integer output as a garbage value and not 10? Isn't TestNum added on the stack, and is "replaced" by 10? Also, how come it's garbage when AddToStack() is called, but is outputted 1021 when not?[/QUOTE]Every function is allocated just enough space on the stack to hold it's local variables and store registers which need to be preserved. The address pointed to by TC.Integer probably contains something completely different than an integer after calling AddToStack(10), since it's integer is likely stored at a different part of it's stack frame. Really though, this is a lot of thought going into what is a simple error in code. :P
The stack isn't as simple as that diagram makes it seem. There are platform-specific things that get pushed there during a function call, in addition to the function's parameters and local variables -- things like stack-unwinding information for exception handling, for example. You can't assume that a parameter passed to one function call will be stored at the same memory address on the stack as a local variable in a previous function call. The call to AddToStack() is evidently storing [i]something[/i] at the spot where TestNum used to be, but it's not the 10 that you expect. Dereferencing pointers to variables that have gone out of scope, like what you're doing here with the former location of TestNum after TC.Foo() has returned, causes undefined behavior. You might get the right value, you might get the wrong value, or you might crash your program. Don't do it.
[QUOTE=-SC-Lakitu;21050649]Every function is allocated just enough space on the stack to hold it's local variables and store registers which need to be preserved. The address pointed to by TC.Integer probably contains something completely different than an integer after calling AddToStack(10), since it's integer is likely stored at a different part of it's stack frame. Really though, this is a lot of thought going into what is a simple error in code. :P[/QUOTE] Oh thanks, and yeah that's true. This whole stack thing is pretty crazy. :p Edit: Okay, just read what Wyzard said. And I think I get it. But thank you all. :D
woah i clicked here by accident and my brain exploded.
Sorry, you need to Log In to post a reply to this thread.