How to avoid memory leak in C++? - c++

I have a question on memory leak. Probably a basic one.
map_a is an map of <int, vector<int>*>
ptr is an pointer to an vector of ints.
Inside for loop, I am searching for 'element' in map_a. If pointer is not found, then create a new vector/record in map_a.
C++ pseudo-code:
map map_a;
for ( 1 to 10 ) {
element = <int number come from a different algorithm, diff every time>;
vector<int> *ptr = map_a[element];
if (!ptr) {
ptr = new vector<int>;
map[element] = ptr;
}
ptr->push_back(i);
}
How to free up the memory we are allocation using new? I am sure that we may be having alternate ways to achieve this situation. But how to take this code along? Are there alternatives?

Any pointer in c++ is deallocated just the same way. So if you have a pointer to a vector you can call delete like so:
vector<int> *a = new vector<int>();
delete a;
However I think that most probably there is a better solution to whatever you are trying to do than using a dynamically allocated vector.
EDIT: from your question it is not apparent if the map is empty before the cycle. If it is you can simply iterate over it and call delete for each of its values:
for (auto it = map_a.begin(); it != map_a.end(); ++it) {
delete it->second.
}
However if the map is not empty you will need an auxilary container (say a vector) to store the pointers allocated in this cycle:
map map_a;
vector<vector<int> * > allocated;
for ( 1 to 10 ) {
element = <int number come from a different algorithm, diff every time>;
vector<int> *ptr = map_a[element];
if (!ptr) {
ptr = new vector<int>;
allocated.push_back(ptr);
map[element] = ptr;
}
ptr->push_back(i);
}
for (int i = 0; i < allocated.size(); ++i) {
delete allocated[i];
}

Related

Has the memory leaked?

void foo(int i)
{
char* p = new char[10];
if (i)
{
p = 0;
}
delete[] p;
}
In the above code snippet, p resource was referenced to zero. Will this create a memory leak in my code?
Yes it leaks in case i != 0.
Your variable p points to some address in memory and by doing p = 0; you erase that pointer. So the instruction delete[] p; will work for a nullptr pointer and you'll not free the allocated memory.
For this type of problems we use smart pointers (unique_ptr, shared_ptr, ...) and STL containers and objects like std::string, std::vector<char>, std::list<char> and so on.
So, in your case you have to change code to something like that
{
char* p = new char[10];
if (i)
{
if (p) {
delete[] p;
p = 0;
}
}
if (p) {
delete[] p;
p = 0;
}
}
Inside your function foo, you are setting the value of the pointer p, which actually is a pointer to the beginning of your dynamic array, to 0 if i is non-zero:
if(i)
{
p = 0;
}
Therefore, when i is non-zero, p no longer points to the start of your array and the delete command will fail to deallocate the array that you create inside the function.
So yes, when i is non-zero, your function will leak memory. I wouldn't change p if I were you. Keep that unchanged until the end so that you call delete [] on it and deallocate the array.
Alternatively, consider using a std::vector instead:
std::vector<char> vec(10);
This does something equivalent except it will take care of the memory allocation/deallocation for you automatically.

How to convert an array of string pointers into a vector of smart pointers of type string?

I have a code like this:
std::string* string_ptr[] = { new std::string("x"), new std::string("y"), new std::string("z") };
I need to get a vector like this:
std::vector<std::unique_ptr<string>> vec;
I also need to clear memory in the original string_ptr array and in the new vector.
How to do it better?
If u want to transfer the ownership to a vector, you can do as follows (after this u won't have to free any memory. the vector will manage that)
int main() {
std::string* string_ptr[] = { new std::string("x"), new std::string("y"), new std::string("z") }; // step 1
size_t sze = size(string_ptr);
std::vector<std::unique_ptr<std::string>> vec(sze); // step 2
for(size_t i{}; i < sze; ++i){
vec[i].reset( string_ptr[i]);
string_ptr[i] = nullptr;//transfer the elments ownership
}
}
If you want to copy them only(you will have to manage the memory held by the raw pointers)
int main() {
std::string* string_ptr[] = { new std::string("x"), new std::string("y"), new std::string("z") }; // step 1
size_t sze = size(string_ptr);
std::vector<std::unique_ptr<std::string>> vec(sze); // step 2
for(size_t i{}; i < sze; ++i){
;
vec[i].reset(new std::string{*string_ptr[i]});
}
vec.erase(vec.end()-1);
}
See Why can I not push_back a unique_ptr into a vector?
You could write
std::vector<std::unique_ptr<std::string>> vec{&string_ptr[0], &string_ptr[3]};
This transfers the pointers into std::unique_ptr<std::string> objects inside the vector. But keep in mind, you don't need to free the strings in string_ptr since they are now held by the unique pointers inside the vector.
Some further advice: Don't allocate strings in an array and transfer them later to the vector. This isn't exception safe. There will be memory leaks if an exception occurs until the end of the second step. If possible, don't use pointers at all:
std::vector<std::string> vec{ "x", "y", "z" };
or put the string pointers right away into the container:
std::vector<std::unique_ptr<std::string>> vec;
vec.emplace_back(std::make_unique<std::string>("x"));
// ...

I allocate memory for a Pair object but fail to place the object there

I would like to have a dynamic array of pointers to pointers to Pair elements;
int m_size = 0;
Pair** ar = new Pair*[++m_size];
*ar[0] = Pair(key, data);
Here I get:
Unhandled exception at 0x013729db in lab3.exe: 0xC0000005: Access violation writing location 0xcdcdcdcd.
It happened in the overloaded operator for MyString (HERE marks when the exception threw):
MyString & MyString::operator = (const MyString & refMyString){
HERE: this->m_pStr = refMyString.m_pStr;
return *this;
}
My classes (a bit simplified for our purpose):
class Pair{
MyString m_key;
Data* m_data;
}
class MyString
{
char* m_pStr;
}
And here is what I get in the debugger:
http://sdrv.ms/ZwkZ9P
http://sdrv.ms/17eoGp6
Well, as far as I can see, when I did Pair** ar = new Pair*[++m_size], a new pointer to pointer to a space for a Pair instance was created. But it is just space in memory. And when I try to operate it, I fail.
And what to do is a mystery to me. Could you help me?
You allocate an array of Pair* but :
1) You never initialize the pointers in that array
2) You dereference those uninitialized pointers (which point to who-knows-where) and overwrite the memory there.
No wonder you get a segfault since you're writing to unallocated memory.
What you (probably?) want to do is:
ar[0] = new Pair(...)
Or better yet, use a standard container (vector, list, deque, ...) instead of C arrays, that will either contain plain objects or smart pointers (unique_ptr or shared_ptr) so that you don't have to manage the memory yourself.
When creating a two dimensional array using a double pointer, you need to allocate both dimensions:
// allocates an array of 10 int* objects
int** p = new int*[10];
for(int x = 0; x < 10; ++x)
{
// Allocates an array of 3 integers
p[0] = new int[3];
}
You would need to ensure that all of the objects you are creating are deleted:
// later
for(int x = 0; x < 10; ++x)
delete [] p[x];
delete [] p;
I would suggest however, just using std::vector so you don't need to manage the memory yourself:
std::vector<std::vector<int>> p;
p.resize(10);
for(int x = 0; x < 10; ++x)
{
p[x].resize(3);
}

Accessing an entire row of a multidimensional array in C++

How would one access an entire row of a multidimensional array?
For example:
int logic[4][9] = {
{0,1,8,8,8,8,8,1,1},
{1,0,1,1,8,8,8,1,1},
{8,1,0,1,8,8,8,8,1},
{8,1,1,0,1,1,8,8,1}
};
// I want everything in row 2. So I try...
int temp[9] = logic[2];
My attempt throws the error:
array initialization needs curly braces
I know I can retrieve the row using a FOR loop, however I'm curious if there was a more obvious solution.
That's not how arrays/pointers work in C++.
That array is stored somewhere in memory. In order to reference the same data, you'll want a pointer that points to the the beginning of the array:
int* temp = logic[2];
Or if you need a copy of that array, you'll have to allocate more space.
Statically:
int temp[9];
for (int i = 0; i < 9; i++) {
temp[i] = logic[2][i];
}
Dynamically:
// allocate
int* temp = new int(9);
for (int i = 0; i < 9; i++) {
temp[i] = logic[2][i];
}
// when you're done with it, deallocate
delete [] temp;
Or since you're using C++, if you want to not worry about all this memory stuff and pointers, then you should use std::vector<int> for dynamically sized arrays and std::array<int> for statically sized arrays.
#include <array>
using namespace std;
array<array<int, 9>, 4> logic = {
{0,1,8,8,8,8,8,1,1},
{1,0,1,1,8,8,8,1,1},
{8,1,0,1,8,8,8,8,1},
{8,1,1,0,1,1,8,8,1}
}};
array<int, 9> temp = logic[2];
As well as decaying the array to a pointer, you can also bind it to a reference:
int (&temp)[9] = logic[2];
One advantage of this is it will allow you to use it C++11 range-based for loops:
for (auto t : temp) {
// stuff
}
A direct assignment won't work. C++ does not allow that. At best you'll be able to assign them to point to the same data - int *temp = logic[2]. You'll need a for loop or something like the below.
I believe this would work:
int temp[9];
memcpy(temp, logic[2], sizeof(temp));
But I'd generally suggest using std::vector or std::array instead.

C++ How to return an array from a function?

I'm brand new to C++ and am having trouble trying to get a function (which takes an array) to return an array. The function is a very basic sorting algorithm for an array of integers of size 4. What i have is below:
int[] sortArrayAscending(int arrayToSort[3]) {
int sortedArray[3];
sortedArray[0] = minOfFour(arrayToSort[0],arrayToSort[1],arrayToSort[2],arrayToSort[3]);
sortedArray[1] = lowerMidOfFour(arrayToSort[0],arrayToSort[1],arrayToSort[2],arrayToSort[3]);
sortedArray[2] = higherMidOfFour(arrayToSort[0],arrayToSort[1],arrayToSort[2],arrayToSort[3]);
sortedArray[3] = maxOfFour(arrayToSort[0],arrayToSort[1],arrayToSort[2],arrayToSort[3]);
return sortedArray;
}
I think i'm getting really confused with the syntax i need to use (the function calls to min, lower, higher, max all work fine.
I would really appreciate some help.
Thank you
EDIT2: Thank you for all the comments. I have now solved it thanks to #Rook's and #Bob Yoplait's answers. The code is used is:
int* sortArrayAscending(int arrayToSort[4], int sortedArray[4]) {
sortedArray[0] = minOfFour(arrayToSort[0],arrayToSort[1],arrayToSort[2],arrayToSort[3]);
sortedArray[1] = lowerMidOfFour(arrayToSort[0],arrayToSort[1],arrayToSort[2],arrayToSort[3]);
sortedArray[2] = higherMidOfFour(arrayToSort[0],arrayToSort[1],arrayToSort[2],arrayToSort[3]);
sortedArray[3] = maxOfFour(arrayToSort[0],arrayToSort[1],arrayToSort[2],arrayToSort[3]);
return sortedArray;
}
int _tmain(int argc, _TCHAR* argv[])
{
int testNumbers[4] = {8,14,1,27};
int testSorted[4];
sortArrayAscending(testNumbers,testSorted);
for (int i = 0; i < 4; i++) {
cout << testSorted[i] << endl;
}
system("pause");
return 0;
}
Thank you for all your help - now time to lookup vectors!
PS I appreciate #Luchian Grigore's solution is most likely the best practise way of doing things, but that wasn't specifically my question
Me, I'd probably use std::array<int, 4> if I was using a modern C++ compiler. Deals nicely with bounds checking and memory management and returning from/passing into functions. You can also use existing STL sort mechanisms and functions upon it; no need to reinvent the wheel!
Now, in your case,
int sortedArray[3];
is a local variable and you should never return a reference to it directly. You could do something like :
int* sortedArray = new int[4];
// do stuff
return sortedArray;
(also note the size of the array, 4, not 3 in your case!) but in this case you have to remember to delete the array at some point in the future or your application will leak memory.
You can also pass in the array by reference, using an approach like
void sort_array(std::array<int, 4>& the_array);
or
void sort_array(int** the_array)
and in these cases you can modify the array in place, or copy the answer into the argument when you're done sorting.
EDIT: After your edit, you, your function returns a pointer to an array. Should work.
You can either return a pointer or a std::vector.
Note that in your code, you'd be running into undefined behavior, because sortedArray goes out of scope at the end of the method, and the memory is freed.
I'd do this instead:
std::vector<int> sortArrayAscending(int arrayToSort[4]) {
std::vector<int> sortedArray(4);
sortedArray.push_back( minOfFour(arrayToSort[0],arrayToSort[1],arrayToSort[2],arrayToSort[3]));
sortedArray.push_back( lowerMidOfFour(arrayToSort[0],arrayToSort[1],arrayToSort[2],arrayToSort[3]));
sortedArray.push_back( higherMidOfFour(arrayToSort[0],arrayToSort[1],arrayToSort[2],arrayToSort[3]));
sortedArray.push_back( maxOfFour(arrayToSort[0],arrayToSort[1],arrayToSort[2],arrayToSort[3]));
return sortedArray;
}
Actually, I wouldn't. I'd just use std::sort instead of creating my own function, but that's just me.
As this is C++, suggest using a std::vector<int> instead:
std::vector<int> sortArrayAscending(int arrayToSort[3]) {
std::vector<int> sortedArray(4); // Note 4, not 3.
sortedArray[0] = ...;
sortedArray[1] = ...;
sortedArray[2] = ...;
sortedArray[3] = ...;
return sortedArray;
}
Note there are several algorithms already available that will perform some of the tasks that you appear to be performing:
max_element()
min_element()
You are returning pointer to local variable, which leads to undefined behavior. sortedArray is statically allocated array with automatic storage duration, which means that memory where it resides is being freed once you leave the scope of the function.
You should allocate it dynamically by using new[] or even better: use std::vector instead. If you choose to allocate it by using new[], don't forget to free it by calling delete[] when you don't need this memory anymore.
Also note that int sortedArray[3]; declares an array of size of 3 elements indexed from 0 to 2. If you access 4th element of the array whose size is 3 (if you access the memory "past the last element of the array object"), the behavior is undefined as well.
Use Boost::Array (or std::array in C+11) that provides proper value semantic to C array.
boost::array<int,4> sortArrayAscending(boost::array<int,4>7 arrayToSort)
{
boost::array<int,4> sortedArray;
sortedArray[0] = minOfFour(arrayToSort[0],arrayToSort[1],arrayToSort[2],arrayToSort[3]);
sortedArray[1] = lowerMidOfFour(arrayToSort[0],arrayToSort[1],arrayToSort[2],arrayToSort[3]);
sortedArray[2] = higherMidOfFour(arrayToSort[0],arrayToSort[1],arrayToSort[2],arrayToSort[3]);
sortedArray[3] = maxOfFour(arrayToSort[0],arrayToSort[1],arrayToSort[2],arrayToSort[3]);
return sortedArray;
}
It is not like in Java
Either you pass sortedArray as a parameter to the func
int* sortArrayAscending(int* arrayToSort, int* sortedArray) {
sortedArray[0] = minOfFour(arrayToSort[0],arrayToSort[1],arrayToSort[2],arrayToSort[3]);
sortedArray[1] = lowerMidOfFour(arrayToSort[0],arrayToSort[1],arrayToSort[2],arrayToSort[3]);
sortedArray[2] = higherMidOfFour(arrayToSort[0],arrayToSort[1],arrayToSort[2],arrayToSort[3]);
sortedArray[3] = maxOfFour(arrayToSort[0],arrayToSort[1],arrayToSort[2],arrayToSort[3]);
return sortedArray;
}
void toto() {
int array[4]; // and fill values...
int sortedArray[4];
sortArrayAscending(array, sortedArray);
}
or
int* sortArrayAscending(int* arrayToSort) {
int* sortedArray = new int[4];
sortedArray[0] = minOfFour(arrayToSort[0],arrayToSort[1],arrayToSort[2],arrayToSort[3]);
sortedArray[1] = lowerMidOfFour(arrayToSort[0],arrayToSort[1],arrayToSort[2],arrayToSort[3]);
sortedArray[2] = higherMidOfFour(arrayToSort[0],arrayToSort[1],arrayToSort[2],arrayToSort[3]);
sortedArray[3] = maxOfFour(arrayToSort[0],arrayToSort[1],arrayToSort[2],arrayToSort[3]);
return sortedArray;
}
and then you need to delete the returned array in the second case.
Arrays are always passed by reference to any function in C++.
So, just pass your array to the function. Your original array would get sorted and you can then use it in your program. I believe there is no need to return the array explicitly.