How to avoid memory leaks, with C++ with STL containers? - c++

code snippet below:
//container declared
map<string, structA*>& aMap;
// allocation and insertion to container
structA *item = new structA();
aMap["arrDevAddr"] = item;
However I iterate and free the map value (pointer) at the end of the map getting used.
Now, due to above code snippet, valgrind is flagging me as "definitely leaked" message.
I want to clarify, the general principle of coding to avoid memory leak. As per my understanding, in (C++ coding):
when we allocate a memory, we are entitled to free it aswell, limted by the overall span of code.
when we keep the allocated memory in some container (e.g. map here), we still need to retain those pointers (allocations), until the map is using those pointers.
which means, allocate >> add pointer to container >> usage of pointers in the map >> ensure "deleting/freeing" the struct-pointers, when the map use is over, or if the map is contained in some object, then in the object's "destructor", map should be iterated and struct-pointers should be freed.
correct me, if I am wrong in my understanding.
SECOND CASE:
class A{
...
map<string, structA*>& aMap;
...
}
now in some other class, the map is inserted with value as;
if(..)
{ structA item;
aObj->aMap["arrDevAddr"] = &item;
}
...
Now, in this case, as "item" is local to the scope, will the map be containing the "dangling references"? If not, how?
In such scenario's what should be the way to ensure, we avoid any memory-leaks while coding?

Don't delete or free things yourself. Always use a memory-managing class- these are completely immune to memory leaks and such related problems unless you work very hard to do something very stupid.
In this case something like unique_ptr would be fine, or even just storing structA by value.

You would avoid memory leaks by storing a std::unique_ptr rather than a raw pointer:
#include <iostream>
#include <map>
#include <memory>
#include <string>
struct structA {};
using structA_ptr = std::unique_ptr<structA>;
//container declared
std::map<std::string, structA_ptr> aMap;
using namespace std;
int main()
{
aMap.emplace("bob", structA_ptr { new structA {} });
return 0;
}

Related

How to write a destructor for a class which includes a map<int,*double> member?

I have a class like:
class CPR_data{
public:
/*some functions*/
private:
map<int,double*> data; //saving data
};
In the file main.cpp, I add data into the class as following:
double *data_ = new double[n_var];
auto insert_flag = data.insert(make_pair(n,data_));
I used the default destructor but it seems a Memory Leak. Do I need to delete all the arrays manually in the destructor?
You loop through your map and call delete[] on every element.
~CPR_data()
{
for(auto& elem : data)
{
delete[] elem.second;
}
}
Note that you now also have to write your own copy constructor and copy assignment operator.
However, the real solution is to use std::map<int, std::vector<double>> instead so you won't have to do any bookkeeping and any questioning about who owns what pointer etc. There's a good chance it'll be as fast as your dynamic allocation method.
You really shouldn't be using any dynamic allocation in C++11 since everything nowadays has a better alternative unless you're writing a standard library implementation or some other exotic piece of code.
#include <iostream>
#include <map>
#include <vector>
using namespace std;
int main()
{
map<int, vector<double>> data;
vector<double> data_ = { 1.0, 2.0, 3.0, 4.0, 5.0 };
auto insert_flag = data.insert(make_pair(1, data_));
vector<double> data_2 = { 1.1, 2.2, 3.3, 4.4 };
insert_flag = data.insert(make_pair(2, data_2));
for(const auto& val : data[2])
cout << val << '\n';
return 0;
}
You don't need to implement your own destructor just for that case. The only thing you have to ensure is to make the double* get deleted when your object is destroyed.
Implementing a destructor that will run through all items is one option, but you can also (as others said) switch to using some other element type. vector is one option, but surely that's not an array.
If you need to stick with raw dynamic arrays, you can always wrap the raw pointer into a smart pointer that will keep track of it and will delete it appropriately.
#include <iostream>
#include <map>
#include <boost/scoped_array.hpp>
int main()
{
std::map<int,boost::scoped_array<double>> data;
int n = 250;
double* data_ = new double[n]; // POTENTIAL LEAK
data_[249] = -1; // POTENTIAL LEAK
/* ... */ // POTENTIAL LEAK
auto insert_flag = data.insert(std::make_pair(n,data_));
std::cout << insert_flag.first->first << " " << insert_flag.second << std::endl;
std::cout << data[250][249] << std::endl;
}
Please be careful with smart pointer type - here I'm using scoped_array as opposed to typical scoped_ptr which is appropriate only for pointers to single object. For dynamic arrays, scoped_array is needed.
Nevertheless, as you can see above, using smart pointer is very similar to using raw pointer. Smart pointers were designed to be as much similar in use as possible. They come with their own destructors, so when the (default) destructor of your object kicks in, it destroys the map, which in turn destroys its elements - and now the elements are smart-pointer - so they will deallocate the arrays.
Actually, I still would encourage you to use vector or whatever else than raw pointers. With raw dynamic allocations you have to be extra careful because even in my example above, there is a tiny possibility of a memory leak - if anything interrupts the code (i.e. exception) between new'ing the raw pointer and packing the pointer into scoped one - nothing will deallocate the raw dynamic array. For that reason, it's best to wrap them as soon as possible and ensure, as hard as it can be, that nothing can interrupt the flow before the raw pointer starts being managed by smart pointer object.
And, as last line - be sure to check out the difference between scoped and shared smart pointers. I used scoped here, because it seems fit. However, it's worth knowing about both types.

new doesn't seem to have a way to grow or shrink allocations?

I have n points in x axis. At the start of the program I am allocating x with npoints. e.g. x = new double[npoints];
During the simulation npoints may vary. If npoints increases I want to increase the allocated memory. Also, if npoints decreases I want to delete that reduced memory.
Use a ::std::vector.
#include <vector>
void foo()
{
::std::vector<double> x;
x.resize(5);
x[4] = 2.0;
x.resize(2);
// etc...
}
The use cases you mention are exactly why ::std::vector was made.
Now, if you resize a vector smaller, it does not normally deallocate memory. This is for a number of reasons, and this StackOverflow question on shrink_to_fit describes why: Is shrink_to_fit the proper way of reducing the capacity a `std::vector` to its size?
But, if you really want to hint to the implementation that the extra points should be deallocated, do this:
#include <vector>
void foo()
{
::std::vector<double> x;
x.resize(5);
x.shrink_to_fit(); // It didn't get smaller here, but I'm guessing you may
x[4] = 2.0; // not know that when you resize the vector in your own code.
x.resize(2);
x.shrink_to_fit();
// etc...
}
The vector still may not actually shrink the allocation. That's an issue to take up with your implementation if it's really a problem.
If it is a problem, and you absolutely have to shrink the allocation and can't get the implementation to be fixed, then you could do this:
#include <iterator>
#include <algorithm>
#include <utility>
#include <vector>
template <class T>
void shrinkwrap_vector(::std::vector<T> &x)
{
using namespace ::std;
typedef vector<T> vec_t;
const auto old_cap = x.capacity();
x.shrink_to_fit(); // Try shrink_to_fit first to see if it works.
if ((x.capacity() == old_cap) && (old_cap > x.size())) {
vec_t t;
t.reserve(x.size());
move(x.begin(), x.end(), back_inserter(t));
swap(x, t);
}
}
then just call
shrinkwrap_vector(x);
in your code instead of x.shrink_to_fit(). That would just copy your vector into a brand new vector that was as close to the size as your implementation would let you get.
Also note that if you're storing something that has a non-trivial destructor (double has a trivial destructor), that destructor will be called for every dropped element when you do a resize. The whole shrink_to_fit thing is solely about memory allocation, not about construction or destruction.
Lastly, if you really, really want to use the C malloc and realloc calls, you might be able to create a custom vector class that uses those. You have to be extra careful though unless you make your custom class specific to double. You have to call the constructor on any elements that are added after the memory is allocated and the destructor on any dropped elements before the memory is deallocated.
Writing this sort of class is complex. You need to conform to the expectation for container classes in C++ to make it work smoothly with everything else. This includes making iterator classes and things of that nature.

std::set for each element in an array

I need a functionality of std::set for each element in an array. How can I achieve this functionality?
I started with allocating dynamic array of std set in C++ as follows:
set<int>* entry;
followed by allocation:
entry = (set<int>*)malloc(sizeof(set<int>)*32);
No compilation problem, but the runtime fails with segmentation fault when any element is accessed:
entry[0].insert(23);
Any help is highly appreciated.
What about
#include <set>
#include <vector>
int main()
{
std::vector < std::set<int> > entry(32); // std::vector constructor makes 32 calls to std::set<int> constructor
entry[0].insert(23);
// std::vector destructor makes 32 calls to std::set<int> destructor
}
In c++ you allocate memory with new. The difference from malloc here is that the constructor is called to initialize the memory.
entry = new set<int>[32];
Even though you've allocated storage for 32 std::set's you haven't initalized this span of memory (ie. the constructor of your std::set's has not been called) therefore the memory you are trying to operate on/access in entry[0].insert (23) will cause undefined behavior.
Mixing C++ objects with malloc and it's equivalent is normally (I'm tempted to write "always") considered to be bad practice.
Instead turn to operator new which will allocate memory and handle construction of your object in a proper manner, also remember to delete the memory allocated to release the memory back to your system (and make the object(s) destruct in a true manner).
The proper way to do it in C++
Some answers will contain text saying that you are better of using a std::vector<std::set>, though that isn't really an answer to your question so I'll leave you with this example snippet
int
main (int argc, char *argv[])
{
std::set<int> *entries = new std::set<int> [32];
entries[0].insert (123);
delete [] entries;
}
This is a good question, whose answer is not immediately obvious. The trouble is that each set object wants to be initialized before it is used, whereas your code only allocates raw memory for each set. This fixes it:
#include <vector>
#include <set>
using std::vector;
using std::set;
const int N = 32;
int main() {
vector< set<int> > entry(N);
entry[0].insert(23);
return 0;
}
Not try to use malloc/calloc/realloc etc with c++ classes. Use new.

C++ Allocate Memory Without Activating Constructors

I'm reading in values from a file which I will store in memory as I read them in. I've read on here that the correct way to handle memory location in C++ is to always use new/delete, but if I do:
DataType* foo = new DataType[sizeof(DataType) * numDataTypes];
Then that's going to call the default constructor for each instance created, and I don't want that. I was going to do this:
DataType* foo;
char* tempBuffer=new char[sizeof(DataType) * numDataTypes];
foo=(DataType*) tempBuffer;
But I figured that would be something poo-poo'd for some kind of type-unsafeness. So what should I do?
And in researching for this question now I've seen that some people are saying arrays are bad and vectors are good. I was trying to use arrays more because I thought I was being a bad boy by filling my programs with (what I thought were) slower vectors. What should I be using???
Use vectors!!! Since you know the number of elements, make sure that you reserve the memory first (by calling myVector.reserve(numObjects) before you then insert the elements.).
By doing this, you will not call the default constructors of your class.
So use
std::vector<DataType> myVector; // does not reserve anything
...
myVector.reserve(numObjects); // tells vector to reserve memory
You can use ::operator new to allocate an arbitrarily sized hunk of memory.
DataType* foo = static_cast<DataType*>(::operator new(sizeof(DataType) * numDataTypes));
The main advantage of using ::operator new over malloc here is that it throws on failure and will integrate with any new_handlers etc. You'll need to clean up the memory with ::operator delete
::operator delete(foo);
Regular new Something will of course invoke the constructor, that's the point of new after all.
It is one thing to avoid extra constructions (e.g. default constructor) or to defer them for performance reasons, it is another to skip any constructor altogether. I get the impression you have code like
DataType dt;
read(fd, &dt, sizeof(dt));
If you're doing that, you're already throwing type safety out the window anyway.
Why are you trying to accomplish by not invoking the constructor?
You can allocate memory with new char[], call the constructor you want for each element in the array, and then everything will be type-safe. Read What are uses of the C++ construct "placement new"?
That's how std::vector works underneath, since it allocates a little extra memory for efficiency, but doesn't construct any objects in the extra memory until they're actually needed.
You should be using a vector. It will allow you to construct its contents one-by-one (via push_back or the like), which sounds like what you're wanting to do.
I think you shouldn't care about efficiency using vector if you will not insert new elements anywhere but at the end of the vector (since elements of vector are stored in a contiguous memory block).
vector<DataType> dataTypeVec(numDataTypes);
And as you've been told, your first line there contains a bug (no need to multiply by sizeof).
Building on what others have said, if you ran this program while piping in a text file of integers that would fill the data field of the below class, like:
./allocate < ints.txt
Then you can do:
#include <vector>
#include <iostream>
using namespace std;
class MyDataType {
public:
int dataField;
};
int main() {
const int TO_RESERVE = 10;
vector<MyDataType> everything;
everything.reserve( TO_RESERVE );
MyDataType temp;
while( cin >> temp.dataField ) {
everything.push_back( temp );
}
for( unsigned i = 0; i < everything.size(); i++ ) {
cout << everything[i].dataField;
if( i < everything.size() - 1 ) {
cout << ", ";
}
}
}
Which, for me with a list of 4 integers, gives:
5, 6, 2, 6

C++ memory management for a vector with variable length items

Take a variable length struct (if this were a real program, an int array would be better):
#include <vector>
struct list_of_numbers(){
int length;
int *numbers; //length elements.
};
typedef std::vector<list_of_numbers> list_nums; //just a writing shortcut
(...)
And build a vector out of it:
list_nums lst(10); //make 10 lists.
lst[0].length = 7; //make the first one 7 long.
lst[0].X = new int[7]; //allocate it with new[]
(...)
The above works for g++ in ubuntu. The new() calls are needed to avoid segfaults. Can the lst vector be deleted all at once when it is no longer needed, or will the new calls cause a memory leak? It would be tedious to manually delete() all of the parts called with new().
The typical ways to do this in C++ would be to define constructors and destructors and assignment operators for the list_of_numbers struct that take care of the memory management, or (much better) use a std::vector<int> for the numbers field and get rid of the length field.
But if you do that, you may as well get rid of the struct entirely, and just do this:
#include <vector>
typedef std::vector<int> list_ints;
typedef std::vector<int_ints> list_lists;
(...)
list_lists lst(10); // make 10 lists.
lst[0].resize(7); // set length of the zeroth list to 7
Why not just use a vector of vector of int? That's it's job. You should not be calling new outside of a dedicated class.
In general, you would want to put cleanup code in the destructor of the object (~list_of_numbers()) and memory creating code in the constructor (list_of_numbers()). That way these things are handled for you when the destructor is called (or when the object is created).