I'm in the process of learning C , and I would like to understand how new
and delete
work for primitive types, and if there is any automatic memory management at all when not using smart pointers.
I have written the following code that tries to trigger a memory leak by repeatedly allocating memory for 10'000 integers in the heap (that is, if I understood how new
works).
#include <iostream>
#include <string>
#include <algorithm>
int* MemoryLeak(const int size) {
std::cout << "Allocating space for " << size << " ints..." << std::endl;
return new int[size];
}
int main() {
std::string keepGoing = "y";
while (keepGoing != "n") {
std::cout << "Leak memory? [y/n]" << std::endl;
std::cin >> keepGoing;
std::transform(keepGoing.begin(), keepGoing.end(), keepGoing.begin(), ::tolower);
if (keepGoing == "y") {
MemoryLeak(10000);
} else if (keepGoing != "n") {
keepGoing = "y";
}
}
}
I don't have a corresponding delete
call, so I would expect the memory footprint of my program to grow after each "y" I enter. However, memory footprint stays the same (according to my task manager). Why is that? And how would I have to modify my snippet in order to cause a leak?
CodePudding user response:
As noted in comments, your compiler and/or operating system may be optimizing away the problem entirely.
So let's do a few things differently:
- Allocate bigger blocks of memory.
- Use the return of
MemoryLeak
and write to it.
#include <iostream>
#include <string>
#include <algorithm>
int* MemoryLeak(const int size) {
std::cout << "Allocating space for " << size << " ints..." << std::endl;
return new int[size];
}
int main() {
std::string keepGoing = "y";
while (keepGoing != "n") {
std::cout << "Leak memory? [y/n]" << std::endl;
std::cin >> keepGoing;
std::transform(keepGoing.begin(), keepGoing.end(), keepGoing.begin(), ::tolower);
if (keepGoing == "y") {
int *x = MemoryLeak(10000000);
for (std::size_t i = 0; i < 10000000; i )
x[i] = i;
} else if (keepGoing != "n") {
keepGoing = "y";
}
}
}
If, as mentioned in comments, we use smart pointers, the memory usage of the program remains constant because when the std::unique_ptr<int[]>
goes out of scope, it is destroyed and the memory deallocated.
#include <iostream>
#include <string>
#include <algorithm>
#include <memory>
std::unique_ptr<int[]> MemoryLeak(const int size) {
std::cout << "Allocating space for " << size << " ints..." << std::endl;
return std::make_unique<int[]>(size);
}
int main() {
std::string keepGoing = "y";
while (keepGoing != "n") {
std::cout << "Leak memory? [y/n]" << std::endl;
std::cin >> keepGoing;
std::transform(keepGoing.begin(), keepGoing.end(), keepGoing.begin(),
::tolower);
if (keepGoing == "y") {
auto x = MemoryLeak(10000000);
for (std::size_t i = 0; i < 10000000; i )
x[i] = i;
} else if (keepGoing != "n") {
keepGoing = "y";
}
}
}
Of course, in practice we would likely not create a unique pointer to an array but rather achieve that effect with a std::vector
.