int main()
{
int *memory = new int[5];
cout << "Memory starts at: " << &memory[0]; // 0x56225460beb0
memory = new int[10];
cout << "\nMemory starts at: "<< &memory[0]; // 0x56225460c2e0
// different
cout << '\n';
return 0;
}
Is there a way to expand the previously initialized memory in C++, when initialized with new. Code above ends up creating a new memory location for memory. Does it also mean that previously allocated memory ends up taking space in my memory, because I didn't delete it
You can use std::vector, which for the most part over allocates, so expands without reallocating up to some extent.
You could also use malloc and realloc, which does something similar to vector, but I wouldn't recommend it since you have to manually call operator new and destructors.
You could also design your own allocator which does whatever you wish, but it's a bit more work, so I'd just stick with vector.
You can use realloc that is available from C language.
memory = (int *) realloc(memory, 10);
It would reallocate from the same address.
Related
The main problem was reallocating memory while expanding it and conserving data and the first starting memory address which is used by many other parts of the program (such as a static starting memory)
This doesn't work with realloc because he deallocate the precedent allocated memory and affects another with a new starting memory address:
using namespace std;
int *t = static_cast<int*>(malloc( 2*sizeof(int)));
cout << "address " << t << endl;
t = static_cast<int*>(realloc(t,10*sizeof(int)));
cout << "address " << t << endl;
=========================
// both of the addresses are different
address 0x55c454fc5180
address 0x55c454fc55b0
after testing many solutions (even direct access to the memory by system call), I found this one :
allocator<int> alloc;
int *t = alloc.allocate(2*sizeof(int));
cout << "address " << t << endl;
// reallocating memory using realloc
t = static_cast<int*>(realloc(t, 10*sizeof(int)));
cout << "address " << t << endl;
=========================
// now the addresses are the same
address 0x55c454fc5180
address 0x55c454fc5180
I tried to explain how it's possible but not able to match the both functioning and I want to know why and how it works.
Using realloc on an address allocated with std::allocator, new or anything similar has undefined behavior. It can only be used when the address comes from the malloc/calloc/realloc family of allocation functions. Never mix them.
In general realloc does not guarantee that the address of the allocation remains unchanged. There is no guarantee that realloc will be able to expand the allocation in place (e.g. there might not be enough memory free after the current allocation). It is the defined behavior of realloc to copy the memory block to a new allocation where sufficient space is free in such a situation. This also means that realloc can only be used with trivially-copyable types in C++.
If your program depends on the address of the allocation remaining unchanged, then it can't expand the allocation. You can have one of these, not both.
Also, you are using std::allocator<int> wrong. The argument to .allocate should be the number of elements of the array to allocate, not the number of bytes. Then afterwards you are supposed to call std::allocator_traits<std::allocator<int>>::construct or std::construct_at or a placement-new on each element of the array to construct and start the lifetime of the array elements.
I am not sure why you are trying to use std::allocator here, but it is unlikely that you need it. If you just intend to create an array of int, you should use new int[n], not std::allocator. Or rather don't worry with manual memory management at all and just use std::vector<int>.
I wrote some code in which I attempted to create a pointer on the Free store(Heap memory). I think it's impossible but I tried regardless.
The code below is basically creating a vector of pointers on the heap and then making those pointers in the vector point to some ints on the heap. I want to know if those pointers in the vector called vec are on the heap? I also wanted to know what is the proper way to free up space allocated when using a vector like this. The last delete statement was crashing the program so I commented it out. I don't know if there is a memory leak.
vector<int*> *vec = new vector<int*>();
vec->push_back(new int(1));
vec->push_back(new int(2));
vec->push_back(new int(3));
cout << (*vec)[0] << " " << (*(*(vec))[0]) << endl;
cout << (*vec)[1] << " " << (*(*(vec))[1]) << endl;
cout << (*vec)[2] << " " << (*(*(vec))[2]) << endl;
delete (*vec)[0];
delete (*vec)[1];
delete (*vec)[2];
//delete [] vec;
Any variable can be created in heap, including a pointer.
That said, at the C++ level you don't control where exactly the memory is created.
The most important thing to understand about pointers is that there is nothing special about pointers.
Like all other vector elements, the elements of vec are located in the free store, since that’s where a vector keeps them.
If you want to manually create an int* in the free store, you would say new int*, which will of course return the address of that pointer, so for instance
int** pointer = new int*(nullptr);
However, there is very little point in doing this in practice — I don't think I’ve seen anyone use it in my twenty-odd years of C++.
The c++ way of creating a pointer on the heap is as follows:
int** pointerToPointer = new int*;
The type int** can be read as a pointer to a pointer. Then we use new to allocate a piece of data of type int* (int pointer) on the heap.
If you want to allocate memory for an integer, you can say new int;, as you've done here.
The new keyword will accept any (non-void) type. So if you want to allocate for a pointer (which would be of type int*), you can just say new int*;
A (heavily contrived) example may look like:
int thing = 7;
int **ptr = new int*(&thing);
std::cout << "**ptr = " << **ptr << std::endl;
Notice that since new will return an address pointing to whatever type we allocated (in this case int*), we'll need to assign it to an int** variable.
All this being said, you're very unlikely to ever need to allocate a raw new int*. More than likely, you'd run into something similar if you're were dealing with dynamically allocated multi-dimensional arrays.
But in any of these situations, I'd strongly suggest using more modern memory management methods with Smart Pointers.
Here is a simple program using dynamic memory.
My question is do I have to delete the memory at the and or the struct will take care of it for me?
#include <iostream>
struct Student {
int grade;
char *name;
};
void print(Student name);
int main() {
Student one;
one.grade = 34;
one.name = new char[12];
int i;
for (i = 0; i < 11; ++i) {
one.name[i] = 'a' + i;
}
one.name[i] = '\0';
print(one);
delete[] one.name;
return 0;
}
void print(Student name) {
std::cout << name.name << " has a score of " << name.grade << "\n";
}
There is a simple rule of thumb- for each call of new you should have one call of delete. In this case you should delete one.name like so : delete [] one.name.
Of course you should do that after you no longer need its value. In this case this is immediately before the return.
Memory allocated dynamically using new or malloc must be freed up when you're done with it using delete or free otherwise you'll get Memory leak.
Make difference between delete and delete[]: the first without subscript operator is used to deleted dynamic memory allocated with new for a pointer. The latter is used for deleting an array allocated dynamically.
So in your case:
one.name = new char[12]; // an array of 12 elements in the heap
delete[] one.name; // freeing up memory
char* c = new char('C'); // a single char in the heap
delete c;
Don't mix new, delete with malloc, free:
This is undefined behavior, as there's no way to reliably prove that memory behind the pointer was allocated correctly (i.e. by new for delete or new[] for delete[]). It's your job to ensure things like that don't happen. It's simple when you use right tools, namely smart pointers. Whenever you say delete, you're doing it wrong.
If you don't want to use unique/shared pointers, you could use a constructor for allocating and a destructor for automatically freeing memory.
If the raw pointer in your structure is an observing pointer, you don't have to delete the memory (of course, someone somewhere in the code must release the memory).
But, if the raw pointer is an owning pointer, you must release it.
In general, every call to new[] must have a matching call to delete[], else you leak memory.
In your code, you invoked new[], so you must invoke delete[] to properly release the memory.
In C++, you can avoid bug-prone leak-prone raw pointers, and use smart pointers or container classes (e.g. std::vector, std::string, etc.) instead.
Creating a Structure does not mean it will handle garbage collection in C++
there is no garbage collection so for every memory you allocate by using new you should use delete keyword to free up space. If you write your code in JAVA you wont have to delete as garbage collector will automatically delete unused references.
Actually the structure won't freeup or delete the memory that you have been created. if in case you want to freeup the space you can do as follows.
#include <iostream>
using namespace std;
int main()
{
char *c = new char[12];
delete[] c;
return(0);
}
In C++, I understand that the delete operator, when used with an array, 'destroys' it, freeing the memory it used. But what happens when this is done?
I figured my program would just mark off the relevant part of the heap being freed for re-usage, and continue on.
But I noticed that also, the first element of the array is set to null, while the other elements are left unchanged. What purpose does this serve?
int * nums = new int[3];
nums[0] = 1;
nums[1] = 2;
cout << "nums[0]: " << *nums << endl;
cout << "nums[1]: " << *(nums+1) << endl;
delete [] nums;
cout << "nums[0]: " << *nums << endl;
cout << "nums[1]: " << *(nums+1) << endl;
Two things happen when delete[] is called:
If the array is of a type that has a nontrivial destructor, the destructor is called for each of the elements in the array, in reverse order
The memory occupied by the array is released
Accessing the memory that the array occupied after calling delete results in undefined behavior (that is, anything could happen--the data might still be there, or your program might crash when you try to read it, or something else far worse might happen).
The reasons for it being NULL are up to the heap implementation.
Some possible reasons are that it is using the space for it's free-space tracking. It might be using it as a pointer to the next free block. It might be using it to record the size of the free block. It might be writing in some serial number for new/delete debug tracking.
It could just be writing NULL because it feels like it.
Whenever someone says int* nums = new int[3], the runtime system is required to store the number of objects, 3, in a place that can be retrieved knowing only the pointer, nums. The compiler can use any technique it wants to use, but there are two popular ones.
The code generated by nums = new int[3] might store the number 3 in a static associative array, where the pointer nums is used as the lookup key and the number 3 is the associated value. The code generated by delete[] nums would look up the pointer in the associative array, would extract the associated size_t, then would remove the entry from the associative array.
The code generated by nums = new int[3] might allocate an extra sizeof(size_t) bytes of memory (possibly plus some alignment bytes) and put the value 3 just before the first int object. Then delete[] nums would find 3 by looking at the fixed offset before the first int object (that is, before *num) and would deallocate the memory starting at the beginning of the allocation (that is, the block of memory beginning the fixed offset before *nums).
Neither technique is perfect. Here are a few of the tradeoffs.
The associative array technique is slower but safer: if someone forgets the [] when deallocating an array of things, (a) the entry in the associative array would be a leak, and (b) only the first object in the array would be destructed. This may or may not be a serious problem, but at least it might not crash the application.
The overallocation technique is faster but more dangerous: if someone says delete nums where they should have said delete[] nums, the address that is passed to operator delete(void* nums) would not be a valid heap allocation—it would be at least sizeof(size_t) bytes after a valid heap allocation. This would probably corrupt the heap. - C++ FAQs
I have this function:
char* ReadBlock(fstream& stream, int size)
{
char* memblock;
memblock = new char[size];
stream.read(memblock, size);
return(memblock);
}
The function is called every time I have to read bytes from a file. I think it allocates new memory every time I use it but how can I free the memory once I have processed the data inside the array? Can I do it from outside the function? Processing data by allocating big blocks gives better performance than allocating and deleting small blocks of data?
Thank you very much for your help!
Dynamic arrays are freed using delete[]:
char* block = ReadBlock(...);
// ... do stuff
delete[] block;
Ideally however you don't use manual memory management here:
std::vector<char> ReadBlock(std::fstream& stream, int size) {
std::vector<char> memblock(size);
stream.read(&memblock[0], size);
return memblock;
}
Just delete[] the return value from this function when you've finished with it. It doesn't matter that you're deleting it from outside. Just don't delete it before you finish using it.
You can call:
char * block = ReadBlock(stream, size);
delete [] block;
But... that's a lot of heap allocation for no gain. Consider taking this approach
char *block = new char[size];
while (...) {
stream.read(block, size);
}
delete [] block;
*Note, if size can be a compile time constant, you can just stack allocate block.
I had a similar question, and produced a simple program to demonstrate why calling delete [] outside a function will still deallocate the memory that was allocated within the function:
#include <iostream>
#include <vector>
using namespace std;
int *allocatememory()
{
int *temppointer = new int[4]{0, 1, 2, 3};
cout << "The location of the pointer temppointer is " << &temppointer << ". Locations pointed to by temppointer:\n";
for (int x = 0; x < 4; x++)
cout << &temppointer[x] << " holds the value " << temppointer[x] << ".\n";
return temppointer;
}
int main()
{
int *mainpointer = allocatememory();
cout << "The location of the pointer mainpointer is " << &mainpointer << ". Locations pointed to by mainpointer:\n";
for (int x = 0; x < 4; x++)
cout << &mainpointer[x] << " holds the value " << mainpointer[x] << ".\n";
delete[] mainpointer;
}
Here was the resulting readout from this program on my terminal:
The location of the pointer temppointer is 0x61fdd0. Locations pointed to by temppointer:
0xfb1f20 holds the value 0.
0xfb1f24 holds the value 1.
0xfb1f28 holds the value 2.
0xfb1f2c holds the value 3.
The location of the pointer mainpointer is 0x61fe10. Locations pointed to by mainpointer:
0xfb1f20 holds the value 0.
0xfb1f24 holds the value 1.
0xfb1f28 holds the value 2.
0xfb1f2c holds the value 3.
This readout demonstrates that although temppointer (created within the allocatememory function) and mainpointer have different values, they point to memory at the same location. This demonstrates why calling delete[] for mainpointer will also deallocate the memory that temppointer had pointed to, as that memory is in the same location.
Yes. You may call delete from outside of the function. In this case though, may I suggest using an std::string so you don't have to worry about the management yourself?
first thing to note: memory allocated with new and delete is completely global. things are not automatically deleted when pointers go out of scope or a function is exited. as long as you have a pointer to the allocation (such as the pointer being returned there) you can delete it when ever and where ever you want. the trick, is just makeing sure other stuff doesn't delete it with out you knowing.
that is a benefit with the sort of function structure the fstream read function has. it is fairly clear that all that function is going to do is read 'size' number of bytes into the buffer you provide, it doesn't matter whether that buffer has been allocated using new, whether its a static or global buffer, or even a local buffer, or even just a pointer to a local struct. and it is also fairly clear that the function is going to do nothing more with the buffer you pass it once it's read the data to it.
on the other hand, take the structure of your ReadBlock function; if you didn't have the code for that it would be tricky to figure out exactly what it was returning. is it returning a pointer to new'd memory? if so is it expecting you to delete it? will it delete it it's self? if so, when? is it even a new pointer? is it just returning an address to some shared static buffer? if so, when will the buffer become invalid (for example, overwritten by something else)
looking at the code to ReadBlock, it is clear that it is returning a pointer to new'd memory, and is expecting you to delete it when ever you are done with it. that buffer will never be overwritten or become invalid until you delete it.
speed wise, thats the other advantage to fsream.read's 'you sort out the buffer' approach: YOU get the choice on when memory is allocated. if you are going "read data, process, delete buffer, read data process delete buffer, ect.... " it is going to be alot more efficient to just allocate one buffer (to the maximum size you will need, this will be the size of your biggest single read) and just use that for everything, as suggested by Stephen.
How about using a static char* memblock; It will be initialised just once and it wont allocate memblock a new space everytime.
Since c++11, one can use std::unique_ptr for this purpose.
From https://en.cppreference.com/book/intro/smart_pointers :
void my_func()
{
int* valuePtr = new int(15);
int x = 45;
// ...
if (x == 45)
return; // here we have a memory leak, valuePtr is not deleted
// ...
delete valuePtr;
}
But,
#include <memory>
void my_func()
{
std::unique_ptr<int> valuePtr(new int(15));
int x = 45;
// ...
if (x == 45)
return; // no memory leak anymore!
// ...
}