I have an assignment that requires me to create a "Heap" class that allocates and deallocates memory. I believe that my code works and the solution builds and runs properly but I want to make sure that I am not getting any memory leaks. I also need to add some code that checks if the desired amount to be allocated to the heap is even available...if someone were to allocate a very large amount. How is it possible to check if the memory allocated on the heap is available or NULL if there is not enough memory. Here is my code so far:
#include <iostream>
using namespace std;
class Heap{
public:
double* allocateMemory(int memorySize)
{
return new double[memorySize];
};
void deallocateMemory(double* dMemorySize)
{
delete[] dMemorySize;
};
};
int main()
{
Heap heap;
cout << "Enter the number of double elements that you want to allocate: " << endl;
int hMemory;
const int doubleByteSize = 8;
cin >> hMemory;
double *chunkNew = heap.allocateMemory(hMemory);
cout << "The amount of space you took up on the heap is: " <<
hMemory*doubleByteSize << " bytes" <<
starting at address: " << "\n" << &hMemory << endl;
heap.deallocateMemory(chunkNew);
system("pause");
return 0;
}
It's not necessary to check beforehand, just try to allocate memory and if you can't, then catch the exception. In this case it is of type bad_alloc.
#include <iostream>
#include <new> // included for std::bad_alloc
/**
* Allocates memory of size memorySize and returns pointer to it, or NULL if not enough memory.
*/
double* allocateMemory(int memorySize)
{
double* tReturn = NULL;
try
{
tReturn = new double[memorySize];
}
catch (bad_alloc& badAlloc)
{
cerr << "bad_alloc caught, not enough memory: " << badAlloc.what() << endl;
}
return tReturn;
};
Important note
Be sure to guard against double-freeing memory. One way to do that would be to pass your pointer to deallocateMemory by reference, allowing the function to change the pointer value to NULL, thereby preventing the possibility of delete-ing the pointer twice.
void deallocateMemory(double* &dMemorySize)
{
delete[] dMemorySize;
dMemorySize = NULL; // Make sure memory doesn't point to anything.
};
This prevents problems like the following:
double *chunkNew = heap.allocateMemory(hMemory);
heap.deallocateMemory(chunkNew);
heap.deallocateMemory(chunkNew); // chunkNew has been freed twice!
Related
I am trying to use getrusage(.) and maximum resident set size (maxrss) to check for memory leaks. However, when i purposely try to create a leak, maxrss does not change. Maybe i am not understanding maxrss deeply enough. Here is the code:
#include <iostream>
#include <sys/time.h>
#include <sys/resource.h>
using namespace std;
int main() {
struct rusage r_usage;
getrusage(RUSAGE_SELF, &r_usage);
cout << r_usage.ru_maxrss << "kb\n";
cout << "Allocating...\n";
int a = 100000; // have tried range of numbers
int* memleaktest = new int[a]; // class member
if(!memleaktest)
cout << "Allocation failed";
getrusage(RUSAGE_SELF, &r_usage);
cout << "after allocation " << r_usage.ru_maxrss << "kb\n";
return 0;
}
I get the exact same value after allocatoin (~15000kb).
On Ubuntu x86.
Allocated memory isn't actually mapped until you access it.
If you initialize the array with values, Linux is forced to actually allocate and map new pages:
#include <iostream>
#include <sys/time.h>
#include <sys/resource.h>
using namespace std;
int main() {
struct rusage r_usage;
getrusage(RUSAGE_SELF, &r_usage);
cout << r_usage.ru_maxrss << "kb\n";
cout << "Allocating...\n";
int a = 1000000; // Sufficiently large
int* memleaktest = new int[a](); // Initialized to zero
if(!memleaktest)
cout << "Allocation failed";
getrusage(RUSAGE_SELF, &r_usage);
cout << "after allocation " << r_usage.ru_maxrss << "kb\n";
return 0;
}
On my system, this results in:
4900kb
Allocating...
after allocation 6844kb
Note that compiler optimizations may decide that the array is unused or should be allocated up front, so prefer compiling without them or rewriting the test case in such a way that it can't be optimized.
Due to performance issues the Operating System (OS) allocates resources in chuncks, not each app-request is a new resource. So, when a block of memory is released in the app, the OS may still reserve the chunck where it belongs to.
Why? Consider an app requesting 1G of different 1 byte memory blocks. The OS must track all of them, which means that the total amount of memory is 1G plus 2G*sizeof(pair) needed to store the pairs {begin, size} to identify each memory block.
If you want to detect memory leaks use the good old Valgrind tool.
In this part of my code (receiving the time) I have a dynamically sized array of chars. This is for a school project and dynamically sized arrays are required.
char* msgtime::getTime() {
std::string t;
t.append(std::to_string(hour));
t.append(":");
t.append(std::to_string(minute));
char *charTime = new char[t.length()];
strcpy(charTime, t.c_str());
return charTime;
}
However, I can't delete the charTime since I am returning the value. I tried following another question I saw on here to return it into a char* in the main program then delete that when I'm done with it. The code here is what the function is returning to:
void receive(packet &data, SOCKET con) {
msgtime tim;
cout << "Receiving data" << endl;
int in = recv(con, (char*)&data, sizeof(data), 0);
cout << "Data received: " << in << endl;
tim.updateTime();
char *newTime = tim.getTime();
strcpy(data.time, newTime);
delete[] newTime;
}
Except when I run it I get this error:
HEAP CORRUPTION DETECTED: after Normal block (#183) at 0x00129330
CRT detected that the application wrote to memory after the end of heap buffer.
I need to delete the charTime in the getTime function to plug the memory leak but I can't figure out how to do it. Any help is GREATLY appreciated!
You don't allocate enough space, one more char is required to store null terminator:
char *charTime = new char[t.length() + 1];
there is a prototype of a function in my fuu.h. I want to pass default values if there
void MyFunction(
int iError = 0,
std::string * MyProblemString = ""
);
// Some attemts:
void MyFunction(
int iError = 0,
std::string * MyProblemString = std::string{""}; // does not work to, complains about missing '*'
);
void MyFunction(
int iError = 0,
std::string * MyProblemString = &std::string{""}; // does not work to, refering address to temporary value
);
void MyFunction(
int iError = 0,
std::string * MyProblemString = *std::string{""}; // does not work to, overloaded operator not known
);
void MyFunction(
int iError = 0,
std::string * MyProblemString = ""; // could not convert ‘""’ from ‘const char [1]’ to ‘std::__cxx11::string* {aka std::__cxx11::basic_string<char>*}’
);
in my c-file is written:
void MyFunction(
int iError,
std::string * MyProblemString,)
{
// do some stuff
}
With the int it's working fine. How can I make the same thing with the string?
There are some examples with other constructions, but passing a pointer does not work.
const reference default-value
thx
I don't think you understand what pointers do. I'll try to help.
Pointers
int number; // An int
int * pointer; // A valid pointer to an int
int* pointer; // Also a valid pointer to an int
int *pointer; // Also a valid pointer to an int
"number" is a named variable of type integer with a chunk of memory big enough to store an int assigned to it. This chunk of memory is given a memory address.
Pointers are basically like an int, except the number they store is the memory address of another variable - in your case, "number".
The & operator will give you the memory address of the variable you use it on.
&number
This will give you the memory address of your int "number".
pointer = &number; // Pointer now contains the memory address of "number"
Now if you try to use pointer like an int, it will give you the address of "number", not its contents. To access the contents of whatever your pointer is pointing at, prefix it with *.
void main()
{
int number = 56;
int* pointer = number; // INVALID: Pointer now pointing at memory location "56"
int* pointer = &number; // Valid: Pointer now pointing at memory location of number
int* pointer; // DANGEROUS, DO NOT LEAVE HANGING POINTERS -- leads to memory access violations
int *pointer = nullptr; // Safely initialise unused pointer
int size = 32;
pointer = new int; // Allocates a block of memory the size of 1 int. Pointer now points at this memory
pointer = new int[size]; // Allocates an array of 32 ints to pointer. Pointer now points to this block of memory
pointer = new int[8]; // Allocates another array to pointer. Pointer now points at the new array, old array has nothing pointing at it and is lost in memory!
// This is a memory leak. AVOID MEMORY LEAKS AT ALL COSTS, they can produce some of the hardest-to-find bugs you'll come across
delete pointer; // Deletes chunk of memory the size of 1 int at the memory pointer is pointing at
delete[] pointer; // Deletes array of memory following the location pointer is pointing at
// IMPORTANT: ALWAYS use delete with new, delete[] with new[]
// IMPORTANT: NEVER use new or new[] without its delete counterpart, or you will encounter memory leaks
// USEFUL:
if (pointer != nullptr)
{
// Do stuff
}
// Doing this will ensure you don't act upon memory you aren't supposed to mess with
// Print these to console to gain a better understanding.
std::cout << number << std::endl;
std::cout << &number << std::endl;
std::cout << pointer << std::endl;
std::cout << *pointer << std::endl;
system("pause");
}
Pay attention to the output:
Output on my machine (the address will vary when you run it):
56 // number
0035F7E0 // &number
0035F7E0 // pointer
56 // *pointer
Note that "&number" and "pointer" print the same thing
You can use & and * to assign pointers to anything, including pointers to other pointers to other pointers to other pointers to whatever the hell you want. It gets messier the deeper you go with things like that, but the point is (pun unintended) pointers are one of the most versatile and handy (but also dangerous -- MEMORY LEAKS, ACCESS VIOLATIONS, AHHH) things to use in C++.
Hope this helped, post a reply to this answer if you don't understand or if this didn't help you understand your problem.
The problem you are having is because you can't give a default value to a pointer without dealing with the memory the pointer is supposed to point to. If you use a std::string instead of a pointer to std::string then you can use the simple string literal syntax as in MyFunction().
If you need to pass a pointer to a string, because you are planning to manipulate the string or for some other purpose, you can give the string the default value of NULL. Since NULL does not point to any memory, this is a perfectly sane default for a pointer. Then you can check for this value, and allocate a new std::string in that special case. That is what I am doing in MyFunction2.
HOWEVER if you allocate memory, you must free that memory somewhere. In my example, I am freeing the memory inside of MyFunction2 only if I also created it. If the value was supplied, I am not freeing the value, but rather leaving that up to the calling function. How you manage memory will depend on your use case, but don't forget about this crucial step.
#import <iostream>
void MyFunction(
int iError = 1,
std::string MyProblemString = std::string(""))
{
std::cout << "\tiError = " << iError << ", and MyProblemString = " << MyProblemString << std::endl;
}
void MyFunction2(
int iError = 1,
std::string * MyProblemString = NULL)
{
bool shouldFree = MyProblemString == NULL;
if (shouldFree){
MyProblemString = new std::string("");
}
std::cout << "\tiError = " << iError << ", and MyProblemString = " << *MyProblemString << std::endl;
if(shouldFree){
delete MyProblemString;
}
}
int main(){
std::string * test = new std::string("test");
std::cout << "Testing with MyFunction:" << std::endl;
std::cout << "\tTest default arguments:" << std::endl;
MyFunction();
std::cout << "\tTest only first argument:" << std::endl;
MyFunction(0);
std::cout << "\tTest both arguments" << std::endl;
MyFunction(2, *test);
std::cout << std::endl;
std::cout << "Testing with MyFunction2:" << std::endl;
std::cout << "\tTest default arguments:" << std::endl;
MyFunction2();
std::cout << "\tTest only first argument:" << std::endl;
MyFunction2(0);
std::cout << "\tTest both arguments" << std::endl;
MyFunction2(2, test);
delete test;
}
I have here some line of code. What I am trying to do here is that I would like to allocate 10 objects using overloaded operator new and on the 11th "run out of memory" and throw an exception. I added a static member function that reclaims the memory allocated for the 10th object so that I can use the address back and allocate it to a new object.
I'm still on the learning process for c++ so your critics are highly appreciated.
Help me evaluate my program. I don't know how I can reclaim the memory and then use the address to allocate the next new object.
Thank you.
P.S. how can I use 'this' in overload operator new?
#include <iostream>
#include <cstdlib>
using namespace std;
int count=0;
class RunOutOfMemory : public exception{
public:
const char * Message(){
return "Run out of memory!";
}
};
class ObjectAllocation{
public:
ObjectAllocation(){
cout << count << "Object Allocated at " << &this[count] << endl;
}
//Operator new overloaded
void * operator new(){
count++;
if(count>=11){
throw RunOutOfMemory();
}
}
//Reclaim memory allocated for 10th instance
//so that a new object can be instantiate on its memory address
static void reclaim(){
//delete?
}
};
int main(int argc, char * argv[]){
ObjectAllocation * objAlloc;
int counter=0;
cout << &objAlloc << endl;
while(counter<=20){
counter++;
try{
objAlloc = new ObjectAllocation();
cout << &objAlloc[counter] << endl;
}catch(RunOutOfMemory room){
cout << room.Message() << endl;
objAlloc.reclaim();
}
}
}
I am trying to get a grasp on pointers and their awesomeness as well as a better C++ understanding. I don't know why this wont compile. Please tell me what is wrong? I'm trying to initialize the pointer when an instance of the class is created. If I try with a normal int it works fine but when I tried to set it up with a pointer i get this in the console
Running…
Constructor called
Program received signal: “EXC_BAD_ACCESS”.
sharedlibrary apply-load-rules all
Any assistance is appreciated greatly.
Here is the code
#include <iostream>
using namespace std;
class Agents
{
public:
Agents();
~Agents();
int getTenure();
void setTenure(int tenure);
private:
int * itsTenure;
};
Agents::Agents()
{
cout << "Constructor called \n";
*itsTenure = 0;
}
Agents::~Agents()
{
cout << "Destructor called \n";
}
int Agents::getTenure()
{
return *itsTenure;
}
void Agents::setTenure(int tenure)
{
*itsTenure = tenure;
}
int main()
{
Agents wilson;
cout << "This employees been here " << wilson.getTenure() << " years.\n";
wilson.setTenure(5);
cout << "My mistake they have been here " << wilson.getTenure() <<
" years. Yep the class worked with pointers.\n";
return 0;
}
You don't ever create the int that the pointer points to, so the pointer is pointer to an area of memory that doesn't exist (or is used for something else).
You can use new to get a block of memory from the heap, new returns the address of the memory location.
itsTenure = new int;
So now itsTenure holds the memory location you can dereference it to set its value.
The changed constructor is as follows:
Agents::Agents()
{
cout << "Constructor called \n";
itsTenure = new int;
*itsTenure = 0;
}
But you must also remember to delete it using delete
Agents::~Agents()
{
cout << "Destructor called \n";
delete itsTenure;
}
You are just missing a new, in the constructor.
itsTenure = new int;
You don't need to make this a pointer, however. Why are you?
You have to allocate a block of memory for your int, and only then use the address of this block of memory (the pointer). This is done with new :
cout << "Destructor called \n";
itsTenure = new int;
*itsTenure = 0;
Then you have to release the memory in the destructor with delete:
cout << "Destructor called \n";
delete itsTenur;
*itsTenure = 0 does not initialize the pointer. It writes 0 to the location that itsTenure points to. Since you never specified where itsTenure points to, that might be anywhere and the behaviour is undefined (an access violation like you're getting being the most likely result).
You need to allocate memory for *tenure in the constructor:
Agents::Agents()
{
cout << "Constructor called \n";
itsTenure = new int;
*itsTenure = 0;
}