C++ local scopes to reduce memory? [closed] - c++

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
When trying to reduce memory use as much as possible, I have seen some programs use additional local scopes. Is this the best way to reduce footprint? Will the variables be removed from the stack when the brackets close? Would it be better to explicitly delete the objects, or is this equally good? Or would the compiler simply remove extraneous brackets?
void foo()
{
{
int a = 4;
BigObject obj1;
obj1.operations(a);
}
{
double b = 9;
BigObject obj2;
obj2.operations(b);
}
}

Yes, they introduce new scopes. Objects with automatic storage duration, i.e. objects on the stack ("local variables"), will go out of scope at the end of this scope.
You are guaranteed that destructors are called, but you are not guaranteed that the object is actually removed from the stack (since stack is an implementation detail -- the standard only talks about automatic storage duration).
However, there is rarely a performance reason for doing so. Instead, it can be useful when using the RAII pattern.
Note, however, that this only applies to local variables. Dynamically allocated memory, i.e. objects on the heap (that you allocate with new), will not be released until you explicitly delete them.
Dynamically allocated memory will have to be pointed to by pointers. C++ clearly separates the concepts of pointer to BigObject and BigObject. In other words, your program is ill-formed. You should write:
BigObject* obj1 = new BigObject();
// ^-- Important!
You can not delete variables with automatic storage, so that part of your question does not make sense.
Not that instead of using new, you should generally prefer using std::unique_ptr instead:
std::unique_ptr<BigObject> obj1 = make_unique<BigObject>();
The memory allocated for your BigObject will be automatically released when obj1 goes out of scope -- this is the RAII pattern.

I have pondered this in the past, but the reality is it does not actually save space according to my nasty experiment. The locals appear to still stock consecutively on the stack:
int _tmain(int argc, _TCHAR* argv[])
{
int* nasty = NULL;
{
int value = 1;
std::cout << &value << std::endl;
}
{
int value2 = 2;
std::cout << &value2 << std::endl;
}
{
int value3 = 3;
std::cout << &value3 << std::endl;
nasty = &value3;
}
std::cout << nasty[0] << ", " << nasty[3] << ", " << nasty[6] << std::endl;
return 0;
}
Output:
001FFC38
001FFC2C
001FFC20
3, 2, 1

Related

Pointer initialization with new keyword and without it [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed last year.
Improve this question
When I try to declare in another way a pointer I try to use the new keyword and give it a try:
#include<iostream>
using std::cin;
using std::cout;
using std::endl;
int main ()
{
int *p = new int;
*p = 5;
cout << *p << endl;
return 0;
}
but when I try to declare the same pointer but without the new keyword it gives me an error like the code below:
#include<iostream>
using std::cin;
using std::cout;
using std::endl;
int main ()
{
int *p;
*p = 5;
cout << *p << endl;
return 0;
}
So what is the reason for that error and what is the difference between the two ways?
You should know the differences.
int *p;
Here, p is just a variable on the stack. It hasn't been initialized so it does not point to a specific location on the memory. Thus when you dereference it and assign a value to the underlying location you are invoking some undefined behavior. In other words, you haven't yet allocated any space on the heap to store an int. So here:
*p = 5;
you are probably assigning the value 5 to a location that does not belong to your program.
Now here:
int *p = new int;
*p = 5;
this is fine. The new operator will reserve 4 bytes on the heap memory and return its address and that address gets stored in the p and now p contains an actual and legal address of a block of memory capable of storing an int. So it is safe to dereference p and assign a value to the underlying location.
Important note: You should almost never deal with new/delete or new[]/delete[] operators and raw pointers. Instead, you should use smart pointers and stick to RAII as much as possible.
Therefore, the correct way of doing the above would be like this:
#include<iostream>
#include<memory>
using std::cin;
using std::cout;
using std::endl;
int main ()
{
std::unique_ptr<int> p { std::make_unique<int>( 5 ) };
cout << *p << endl;
return 0;
}
However, using any type of pointers is wasteful in this case since you can also store small types on the stack:
int num { 5 };
This is the preferred way of storing values unless you are desperate to use dynamic memory allocations (for some reason, like maybe you want an object to have dynamic storage duration, or maybe the object is large and won't fit on the stack).
new int occupies a new memory space on the heap, and p points to that memory space. But on the second example, you didn't specify where p points to (so p can point to anywhere, but you try to assign the memory address p points, so it cause undefined behaviour.

C++ Stack vs Heap and Pointers [duplicate]

This question already has answers here:
Can a local variable's memory be accessed outside its scope?
(20 answers)
Closed 7 years ago.
So I'm learning C++ (coming from a Java background). I thought I understood how memory works on a high level (stack vs heap and pointers). To experiment, I wrote the following two toy functions:
int* pntrToHeap(int val) {
return new int(val);
}
and
int* pntrToStack(int val) {
return &val;
}
At first I thought pntrToStack just wouldn't work, because the local variable val is on the stack which is "deleted" after the function exits. But after the following code worked without errors (with 1 warning, however), I reconsidered:
int main()
{
int val1 = *pntrToHeap(3);
int val2 = *pntrToStack(4);
cout << val1 << endl;
cout << val2 << endl;
return 0;
}
Both 3 and 4 printed to the screen. It seems as though the stack isn't actually deleted, but the CPU just loses the ability to access local variables on it -- is this correct? If so, in a case like this, which function should we prefer?
Lastly, since val1 is a local variable of main, is pntToHeap creating a memory leak since I can't delete the value it created on the heap?
I know these concepts have been asked about before, but I couldn't quite find the answers. Thanks!
Definitely the first one! If you want something to live after the stack frame expires you should heap allocate it.
And yes, the value pointed to by the pointer returned from pntrToStack will be overwritten the next time you allocate a new stack frame ie. call a function. When you exit out of a scope the memory is not erased. It is merely marked as being free to allocate.

stack variable lifetime curious example [duplicate]

This question already has answers here:
Can a local variable's memory be accessed outside its scope?
(20 answers)
Closed 8 years ago.
Please consider this simple example:
#include <iostream>
const int CALLS_N = 3;
int * hackPointer;
void test()
{
static int callCounter = 0;
int local = callCounter++;
hackPointer = &local;
}
int main()
{
for(int i = 0; i < CALLS_N; i++)
{
test();
std::cout << *hackPointer << "(" << hackPointer << ")";
std::cout << *hackPointer << "(" << hackPointer << ")";
std::cout << std::endl;
}
}
The output (VS2010, MinGW without optimization) has the same structure:
0(X) Y(X)
1(X) Y(X)
2(X) Y(X)
...
[CALLS_N](X) Y(X)
where X - some address in memory, Y - some rubbish number.
What is done here is the case of undefined behaviour. However I want to understand why there is such behaviour in current conditions (and it is rather stable for two compilers).
It seems that after test() call first read of hackPointer leads to valid memory, but second successive instant read of it leads to rubbish. Also on any call address of local is the same. I always thought that memory for stack variable is allocated on every function call and is released after return but I can't explain output of the program from this point of view.
"Releasing" automatic storage doesn't make the memory go away, or change the pattern of bits stored there. It just makes it available for reuse, and causes undefined behaviour if you try to access the object that used to be there.
Immediately after returning from the function, the memory occupied by the local probably hasn't been overwritten, so reading it will probably give the value that was assigned within the function.
After calling another function (in this case, operator<<()), the memory is likely to have been reused for a variable within that function, so probably has a different value.
You are quite right that this is undefined behaviour.
That aside, what's happening is that std::cout << *hackPointer involves a function call: operator<<() gets called after the value of *hackPointer has been read. In all likelihood, operator<<() uses its own local variables that end up on the stack where local was, wiping out the latter.

C++ reverse string [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
Good day,
Please can someone assist? I am trying to reverse a member that is a pointer array.
string::string(char *c)
{
int i =0;
while ((c[i] != '\0'))
{
i++;
}
_lenght= i;
_aString=*&c;
}
void string::reverse() //Requirements specify to have this argument
{
for(int i=0; i<_lenght/2; i++)
{
std::swap(_aString[i], _aString[_lenght-i-1]);
}
}
I get a runtime error on this.
This is my main function
int main(){
string a;
std::cout << "a is " << a << "\n";
string b("12345");
string c("12345",3);
std::cout << "c is " << c << "\n";
c = a;
a = b;
std::cout << "a is " << a << "\n";
b.reverse();
std::cout << "a is " << a << "\n";
return 0;
}
Error I'm getting is
Unhandled exception at 0x00fd6710 in UnisaLesson1.exe: 0xC0000005: Access violation writing location 0x00fdfd08.
Sorry, I'm still a newb.
The problem is
_aString=*&c;
which is a weird way of writing
_aString=c;
so that _aString is simply pointing to whatever the function argument was; this class doesn't manage a the memory for a string (as std::string does), but refers to an external string managed elsewhere.
In your test case, that string is a string literal - which isn't modifiable. So attempting to modify it, as reverse does, gives undefined behaviour; if you're lucky, an access violation; if you're unlucky, data corruption or some other unwanted runtime behaviour.
If your class is supposed to manage the memory, then it will need to allocate it in the constructor. Assuming this assignment is an exercise in memory management (otherwise, just use std::string), you'd want something like
_aString = new char[_lenght];
std::copy(c, c+_lenght, _aString);
and don't forget the Rule of Three:
a destructor to release the memory with delete [] _aString
copy constructor, either deleted to prevent copying, or implemented to allocate a new buffer;
copy-assignment operator, either deleted to prevent copying, or implemented to copy into the existing buffer after resizing if necessary.
You might also consider fixing the spelling of _lenght to _length.

How vector allocate memory

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.