I'm fairly new to C++ so please forgive me for my ignorance. I'm under the impression that anything between { and } is called a scope, and that you can create a separate scope inside a function, or anything else, just by adding more brackets. For example:
int foo(){
std::cout << "I'm inside the scope of foo" << std::endl;
{
std::cout << "I'm inside a scope that's inside the scope of foo" << std::endl;
}
}
I was learning about this in relation to pointers and memory leaks. My understanding is when you leave a scope all variables should be freed from memory unless the memory was manually allocated with new or malloc. In my testing, however, this does not seem to be the case. I've written the following script to test this:
#include <iostream>
void test(){
{
int regdata = 240;
int* pointerInt = new int(1);
*pointerInt = 15;
std::cout << "RegData Addr: " << ®data << std::endl;
std::cout << "Value: " << regdata << std::endl;
std::cout << "Pointer Addr: " << &pointerInt << std::endl;
std::cout << "Pointer: " << pointerInt << std::endl;
std::cout << "Value: " << *pointerInt << std::endl;
std::cout << std::endl;
std::cout << "Press any key then enter to leave the scope.";
char temp;
std::cin >> temp;
//delete pointerInt;
}
std::cout << "The scope has been left." << std::endl;
std::cout << "Press any key then enter to leave the function.";
char temp;
std::cin >> temp;
}
int main(){
test();
std::cout << "The function has been left." << std::endl;
std::cout << "Press any key then enter to leave the program.";
char temp;
std::cin >> temp;
}
I start this program on my Windows 10 computer and have been monitoring the memory usage using the program Cheat Engine. Now, depending on whether or not I have delete commented out it will delete the bytes that hold 15 and replace them with random bytes when I leave the scope as it should. However, the memory holding the 240 is not freed until after I leave the scope of test (at which point the 240 is replaced with 1). And regardless of if the delete is commented out, the actual pointer itself is never deleted out of memory.
Is my compiler or my machine not compiling/running my code correctly? Or am I misunderstanding memory management between scopes? If it's the latter, please correct me so I can properly understand what is supposed to happen. Also let me know if something doesn't make sense!
Memory is not "freed" when you leave a scope. The lifetime of all variables with automatic storage duration that were declared within that scope end. What happens when the lifetime of a variable ends? For simple values like an int or a pointer: likely absolutely nothing. The lifetime of the variable has ended, so attempting to use it results in undefined behavior, but usually nothing will immediately happen to the value. The compiler knows that the storage in which the variable resided is now available to be re-used, but until it actually re-uses it the old value will likely continue to exist. A compiler could immediately zero out the memory of variables whose lifetime has ended, and for a debug build maybe it will, but doing so would take time so most compilers won't bother.
regdata is stored on the stack so the memory it uses will never normally be "freed" until the end of the thread that the code is running in.
What does happen is that the stack memory is now available again to be used for something else. Your calls to std::cout and std::cin will both need to use a certain amount of stack memory, if they use enough memory then they'll overwrite all of the values in your inner scope (depending on the implementation of your compiler, there's no guarantee that it'll reuse the inner scopes stack memory later in the function, it might decide it's faster to use more stack memory instead).
This is why regdata is always being overwritten with 1, it's a coincidence of later stack usage rather than a deliberate action by the compiler. Some compilers might deliberately overwrite stack memory after its released to help with debugging but in a normal release build that would be an unnecessary waste of time.
Related
I am working on a small console game on my free time and have come across a bug I can't seem to fix no matter what I try. I have tried a lot of different things with the pointers so this is just the latest version of my code. I have been searching around and a few questions other's have asked indicated I may be experiencing a memory leak, or that I am reading values from beyond my arrays (don't understand how). However, those questions have been solved without leaving me any hints as to what is wrong with my code.
Basically, I have a function called int * spendAttribute(int point);
Since anything created in that function is out of scope in my main() I want to take 6 int out of that function, and bring them into my main().
I thought "hey why not use a pointer!" The function is supposed to return a pointer to an array created during the function, and paste it to another pointer created in main(), this has worked once before in my main(), but now it's not working and I have no clue why.
int * spendAttribute(int point)
{
string choice;
int hp,hpT,endur,endurT,dmg,dmgT,armor,armorT,agility,agilityT,evade,evadeT;
while(condition)
{
//do a bunch of junk ....
}
int stats[6] = {hp,endur,dmg,armor,agility,evade};
//some cout testing to see if values are correct (they are)
int* p_stats = new int [6]; //create a block of 6
p_stats = &stats[0]; //point to the first value of stats array
return p_stats; //return pointer
delete [] p_stats; //delete blocks
}
Note: I have tried without deleting the blocks and it still does not work. I tried this since I read that it might be a memory leak.I have tried it without using new at all.
main()
{
//.... some junk
while(main game loop)
{
int * pointer;
cout << "*************** Enter 'begin' to commence ****************** " << endl ;
cout << "*************** Enter 'spend' to use new attribute points ** " << endl ;
cin >> beginChoice; //declared before while loop
if(beginChoice == "spend")
{
cout << "total attributes: " << Bryan.returnAttribute() << endl ;
pointer = spendAttribute(Bryan.returnAttribute()); //copy pointer
cout << "TEST: " << endl ;
cout << pointer[0] << endl ; //out put is a bunch of random numbers..
cout << pointer[1] << endl ;
cout << pointer[2] << endl ;
cout << pointer[3] << endl ;
cout << pointer[4] << endl ;
cout << pointer[5] << endl ; //SOME DAMN BUG HERE
Bryan.addMaxHp(pointer[0]);
Bryan.addEndurance(pointer[0]);
Bryan.addDmg(pointer[0]);
Bryan.addArmor(pointer[0]);
Bryan.addAgility(pointer[0]);
Bryan.addEvasion(pointer[0]);
//after this character ends up having some ridiculous stats like -564553535%
//evasion or 9879967856 armor...
}
}
}
This method of transferring the array over to main worked for me before in this exact file, so I don't know exactly how I am getting these errors or what's causing them. I have even tried deleting the previous pointer used to see if thats what was causing it but it wasn't.
Please Halp.
Because you return a pointer to a local variable, and when that local variable goes out of scope you have a stray pointer.
And no, your allocation doesn't help, as you reassign the pointer to point to the local array, instead of copying into the allocated area. This of course means you also have a memory leak.
Regarding memory leak, you will still have a memory leak even when you fix the above problem. The reason being that you return from the function before you delete[] the pointer, and return returns from the function immediately, all code after a return statement is dead code. That means every time you call the function, it will allocate new memory which will never be free'd.
There are two obvious solutions to both the problems above: One is to allocate memory, copy the array into the allocated memory, and returning the pointer, and in the caller you do delete[] on the pointer.
The second solution is to pass in an array as argument, and use that instead of the local stats array.
p_stats is a pointer to int.
First you assign it to a newly allocated place in memory.
Then you move the pointer to point to local storage and return that. My guess is that you really wanted to return stats. Your options are:
Returns std::vector< int >. Probably simplest.
Modify your function to take a buffer to data and a length and fill it in.
Return std::array if available and you know it will be a fixed size of 6.
Although you could copy the data into p_stats then return that, it is not ideal because the calling function is then responsible to delete the data later.
If the fields have different meanings, you might want to create a struct with meaningful names for the values, and get your function to return that struct. e.g.
struct SpendAttribute // in header
{
int hp;
int endur;
int dmg;
int armor;
int agility:
int evade
};
SpendAttribute spendAttribute( int point )
{
SpendAttribute res;
// enter code here
return res;
}
There is a final option of putting the data into a smart-pointer like boost::shared_array<int> or you can use shared_ptr with an array-deleter.
For now, just return std::vector<int>
For example, if loaded a text file into an std::string, did what I needed to do with it, then called clear() on it, would this release the memory that held the text? Or would I be better off just declaring it as a pointer, calling new when I need it, and deleting it when I'm done?
Calling std::string::clear() merely sets the size to zero. The capacity() won't change (nor will reserve()ing less memory than currently reserved change the capacity). If you want to reclaim the memory allocated for a string, you'll need to do something along the lines of
std::string(str).swap(str);
Copying the string str will generally only reserve a reasonable amount of memory and swapping it with str's representation will install the resulting representation into str. Obviously, if you want the string to be empty you could use
std::string().swap(str);
The only valid method to release unused memory is to use member function shrink_to_fit(). Using swap has no any sense because the Standard does not say that unused memory will be released when this operation is used.
As an example
s.clear();
s.shrink_to_fit();
I realized the OP is old but wanted to add some precision. I found this post when I was attempting to understand a behavior that seemed to contredict the answers provide here.
With gcc4.8.3, clear() might look like it's releasing memory in some scenario.
std::string local("this is a test");
std::cout << "Before clear: " << local.capacity() << '\n';
local.clear();
std::cout << "After clear: " << local.capacity() << '\n';
As expected I get
Before clear: 14
After clear: 14
Now lets add another string into the mix:
std::string local("this is a test");
std::string ref(local); // created from a ref to local
std::cout << "Before clear: " << local.capacity() << '\n';
local.clear();
std::cout << "After clear: " << local.capacity() << '\n';
This time I get:
Before clear: 14
After clear: 0
Looks like stdc++ has some optimisation to, whenever possible, share the memory holding the string content. Depending if a string is shared or not the behavior will differ. In the last example, when clear() is called, a new instance of the internal of std::string local is created and it will be empty(). The capacity will be set to 0. One might conclude from the ouput of capacity() that some memory was freed, but that is not the case.
This can be proven with the following code:
std::string local("this is a test");
std::string ref(local); // created from a ref to local
std::cout << (int*)local.data() << ' ' << (int*)ref.data() << '\n';
Will give:
0x84668cc 0x84668cc
The two strings point to the same data, i was not execting that. Add a local.clear() or anything that modifies local or ref and the adresses will then differ, obviously.
Regards
... would this release the memory that held the text?
No.
Or would I be better off just declaring it as a pointer ...
No, you'd be better off declaring the string in the scope in which it is needed, and letting its destructor be called. If you must release the memory in the scope which the string still exists, you can do this:
std::string().swap(the_string_to_clear);
In this example, I create a vector with one integer in it and then I erase that integer from the vector. The size of the vector decreases, but the integer is still there! Why is the integer still there? How is it possible for a vector of size 0 to contain elements?
#include <vector>
#include <iostream>
using namespace std;
int main(int agrc, char* argv[])
{
vector<int> v;
v.push_back(450);
cout << "Before" << endl;
cout << "Size: " << v.size() << endl;
cout << "First element: " << (*v.begin()) << endl;
v.erase(v.begin());
cout << "After" << endl;
cout << "Size: " << v.size() << endl;
cout << "First element: " << *(v.begin()) << endl;
return(0);
}
output:
Before
Size: 1
First element: 450
After
Size: 0
First element: 450
You are invoking undefined behavior by dereferencing an invalid memory location. Normally, the heap manager will not immediately free the memory deleted using delete for efficiency purposes. However, that doesn't mean that you can access that memory location, heap manager can use this memory location for other purposes whenever it likes. So your program will behave unpredictably if you dereference a invalid memory location.
IIRC a vector doesn't release space unless specifically told to, so you're seeing an item which is still in its memory but not being tracked by the vector. This is part of the reason why you're supposed to check the size first (the other being that if you never assigned anything, you'll be dereferencing a garbage pointer).
To start, don't count on it being this way across all systems. How a vector works internally is completely implementation-dependent. By dereferencing an invalid memory location, you're circumventing the behavior that has been outlined in the documentation.
That is to say, you can only count on behavior working that is outlined in the STL docs.
The reason you can still access that memory location is because that particular implementation you are using doesn't immediately delete memory, but keeps it around for awhile(probably for performance purposes). Another implementation could very well delete that memory immediately if the author so desired.
It is just that the vector has not freed the memory, but kept it around for future use.
This is what we call "undefined behaviour" There is no guarantee that it will work next time and it may easily crash the program on a future attempt. Don't do it.
What are your compiler options? I get a crash with the usual
options, with both of the compilers I regularly use (g++ and
VC++). In the case of g++, you have to set some additional
options (-D_GLIBCXX_DEBUG, I think) for this behavior; as far as
I can tell, it's the default for VC++. (My command for VC++ was
just "cl /EHs bounds.cc".)
As others have said, it's undefined behavior, but with a good
compiler, it will be defined to cause the program to crash.
Hii
I know that vector allocated contiguous fixed memory when it needs to push_back some items.And if its not able to fit into it it will alllocate new memory and copy old values into it and delete the old memory.
If that is the case how the following code works
#include<iostream>
#include<vector>
using namespace std;
class Test
{
public :
int val;
Test()
{
val=0;
}
};
int main()
{
vector<Test>vec;
Test t[10];
for (int i=0;i<5;i++)
vec.push_back(t[i]);
cout<<vec.capacity()<<endl; //printing 8
Test* obj=&vec[2];
obj->val=2;
cout<<obj<<endl;
for (int i=0;i<5;i++) //Adding 5 elements more
vec.push_back(t[i]);
Test* obk=&vec[2];
cout<<obk->val<<endl;
cout<<obj->val<<endl;
cout<<obj<<endl;
cout<<obk<<endl;
}
Here if you see obj is taking pointer of vec[2] which value in my machine is coming 0x8bcb048 .Then I am inserting 5 more items so vector will allocate new memory.Now if i am taking obk from vector[2] its coming different address 0x8bcb070 . But if i try to acess i with the help of obj its not giving any problem.Any reason ?
But if i try to access it with the help of obj its not giving any problem. Any reason?
This is undefined behavior - the fact that it appears to work is simply due to luck (whether good or bad luck is matter of opinion).
Essentially you're dereferencing a 'dangling' pointer. and just like if you dereference a pointer to a block of memory that's been freed, you simply read out old, stale data that happens to look like it has reasonable values. or you might read out something that appears to be garbage. Or you might cause a segfault.
One thing is for certain - it's a bug, whether it seems to act like one or not.
vectors are dynamic arrays. You are right when they overflow they are reallocated someplace else and all earlier initialized pointers/ iterators( which generally for vectors are also implemented as pointers, although the standards don't require it)/ address references become invalid. and earlier held memory space is freed finally.
Here is how events occur in simplistic terms:
currently available space is insufficient.
new memory space is acquired ( k times(generally k=2) as large as original memory size)
current array is copied to new memory locations
old = current; current = new; { this ensures atomicity for single insertions}
old memory is freed.
Notice that old memory location's data is not destroyed or reset. So when the resources are needed again that might or might not be reused. But the original memory location that you have is a false location and must be avoid always.
When a vector reallocates, all iterators, pointers and references that you obtained prior to the reallocation are invalidated. Using them leads to undefined behavior, which includes "apparently not giving any problems".
To visualize the problem, you can insert debug outputs in the constructors and the destructor. You could also log which objects exist at any point in time:
class Test;
std::set<Test*> valid_Test_objects;
class Test
{
int val;
public:
Test() : val(0)
{
valid_Test_objects.insert(this);
std::cout << "constructed Test object # " << this << std::endl;
}
Test(const Test& that) : val(that.val)
{
std::cout << "constructed Test object # " << this << std::endl;
valid_Test_objects.insert(this);
}
~Test()
{
std::cout << "destructing Test object # " << this << std::endl;
valid_Test_objects.erase(this);
}
int value()
{
std::cout << " accessing Test object # " << this << std::endl;
if (valid_Test_objects.find(this) == valid_Test_objects.end())
{
abort();
}
return val;
}
};
int main()
{
std::vector<Test> vec;
vec.reserve(3);
Test x;
vec.push_back(x);
Test* p = &vec[0];
std::cout << p->value() << std::endl;
std::vector<Test>::size_type cap = vec.capacity();
while (cap == vec.capacity()) vec.push_back(x);
std::cout << p->value() << std::endl;
}
Unfortunately, we should not even try to call p->value() when p is invalid. Enjoy your stay at undefined behavior land ;-)
If you're asking why there's no crash when you try to access 'obj' then I would say you should try to run it in Release mode and see. In any case, obj should not be accessible, as the pointer that was returned by &vec[2] was invalidated when the vector increased its capacity. It could still be pointing to some random junk that happens to be allocated to your processes.
int main() {
Employee *e = new Employee();
delete e;
delete e;
...
delete e;
return 0;
}
You get undefined behaviour if you try to delete an object through a pointer more than once.
This means that pretty much anything can happen from 'appearing to work' to 'crashing' or something completely random.
It's undefined behavior, so anything can happen.
What's likely to happen is bad. Typically, the free store is a carefully managed system of free and allocated blocks, and new and delete do bookkeeping to keep everything in a consistent state. If you delete again, the system is likely to do the same bookkeeping on invalid data, and suddenly the free store is in an inconsistent state. This is known as "heap corruption".
Once that happens, anything you do with new or delete may have unpredictable results, which can include attempting to write outside the application's memory area, silently corrupting data, erroneously thinking there's no more memory, or double or overlapping allocation. If you're lucky, the program will crash soon, although you'll still have problems figuring out why. If you're unlucky, it will continue to run with bad results.
Aside from the old saw about "undefined behavior" meaning anything could happen from nothing to a gateway to the seventh circle of the inferno opening up in main memory, in practice what will usually happen in most implementations is that the program will continue to run past the deletes, and then mysteriously crash sometime later in some unrelated memory allocation.
You are likely venturing into 'undefined behavior' territory.
On many systems this will cause a crash; for example, on my Linux machine:
*** glibc detected *** ./cctest: double free or corruption (fasttop): 0x0000000000d59900 ***
======= Backtrace: =========
/lib/libc.so.6[0x7f399f4cbdd6]
/lib/libc.so.6(cfree+0x6c)[0x7f399f4d074c]
./cctest[0x400a7a]
/lib/libc.so.6(__libc_start_main+0xfd)[0x7f399f474abd]
./cctest[0x400959]
If you're really lucky it will crash. What normally happens is it stores up karma until your CEO is demonstrating the code to your most important new customer when it will corrupt/destroy all of their data.
In checked or debug builds often this kind of thing is caught, but it can go completely undetected and cause havoc later. This is especially profound when multiple threads get involved.
If you are worried this might happen in your apps, either stop using raw pointers completely, so that you don't need delete (eg switch over to shared_ptr) or always set pointers to NULL (or 0, or better still nullptr) after you delete them. Calling delete on a null pointer is guaranteed to do nothing.
It's not safe, and it's undefined what might actually happen:
http://www.parashift.com/c++-faq-lite/freestore-mgmt.html#faq-16.2
Even though sometimes we can access the memory location after deleting ptr.
we shouldn't delete same pointer again or assign value to that pointer( leads to inconsistent behavior).
But we can use same pointer variable to point different memory address ( valid memory)
int *p = new int(10);
std::cout << "in main" << std::endl;
std::cout <<*p << std::endl;
std::cout << p << std::endl;
std::cout << &p<< std::endl;
delete p;
std::cout << "in main2 after delete" << std::endl;
std::cout <<*p << std::endl;
std::cout << p << std::endl;
std::cout << &p<< std::endl;
p = new int(100);
std::cout << "in main3" << std::endl;
std::cout <<*p << std::endl;
std::cout << p << std::endl;
std::cout << &p<< std::endl;
leads to output
in main
10
0x558b597a8eb0
0x7fff8f7a5ba0
in main2 after delete
0
0x558b597a8eb0
0x7fff8f7a5ba0
in main3
100
0x558b597a8eb0
0x7fff8f7a5ba0