Releasing memory of a struct containing multiple vectors - c++

Having a struct such as:
struct PAIR {
vector<double> a;
vector<double> b;
};
Is using a function like the following a proper way to release the memory after defining and populating such a struct? If not, how do you deal with this situation?
void release(PAIR& p){
vector<double>().swap(p.a);
vector<double>().swap(p.b);
}
Isn't there a way to call some predefined/std function on PAIR itself to release memory?
Note that I'm not using new, etc. so definitions are simply like PAIR p;. Also, the struct is much more complex than just a pair of vectors that could have been defined using a std::pair.
All the related questions in SO on releasing memory for vectors are either about vectors themselves or vectors of a struct, not a struct containing multiple vectors. I'm looking for an elegant way to release memory used by such a struct.
Context
The vectors get really big, and I want to release the memory as soon as I can. But that lifetime/usability reaches in the middle of function! I don't want to spread the functionality in this function to multiple functions. These are pretty complicated computations and don't want to mess things up.

Given function does not release memory on the stack actually. It is approximately equivalent to
p.a.clear();
p.a.shrink_to_fit();
The vector itself remains in the memory (just with 0 elements).
Remember, any memory that was allocated on the stack (~ without the use of new) gets released only when the variable occupying this memory goes out of scope, not earlier.
So if you have a variable on the stack and want to delete it, you can just limit its scope:
struct PAIR {
vector<double> a;
vector<double> b;
};
int main()
{
// some stuff before...
{
PAIR p;
// some stuff with p object...
} // here p gets deleted (all memory gets released)
// some stuff after...
}
You mentioned new PAIR. With pointers it would look like this:
int main()
{
// some stuff before...
PAIR* p = new PAIR;
// some stuff with p object...
delete p; // here p gets deleted (all memory gets released)
// some stuff after...
}
Or as commentators requested:
int main()
{
// some stuff before...
{
auto p = std::make_unique<PAIR>();
// some stuff with p...
} // here p gets deleted (all memory gets released)
// some stuff after...
}
Is that what you wanted to achieve?

Does PAIR have to be a POD? Maybe something like this might work for you?
struct PAIR
{
private:
std::unique_ptr<std::vector<double>> aptr;
std::unique_ptr<std::vector<double>> bptr;
PAIR(const PAIR&) = delete;
public:
PAIR() : aptr(std::make_unique<std::vector<double>()),
bptr(std::make_unique<std::vector<double>()) {}
~PAIR() { release(); }
std::vector<double> &a = *aptr;
std::vector<double> &b = *bptr;
void release()
{
aptr.reset();
bptr.reset();
}
...
};

simply .resize(0) the vectors.

Related

How to take ownership of an object while looping over std::vector of std::unique_ptr using a range based for loop?

I have a std::vector<std::unique_ptr<Kind>> which I want to clean up while it is being iterated upon, without explicitly calling the destructor of its members (.reset()).
The Kind is a heavy struct and its size increases during the iteration. The next object doesn't need to know about previous objects so I'd like to clean up an iterand when its not needed.
I know vector will clean up in the end, but by then, lots of Kind and their dynamically allocated memory adds up. I'm trying to reduce peak memory to just one element.
I want to avoid reset since other developers may not know about the dynamic allocation, forget calling reset in the end of the loop and cost memory penalty.
I cannot create a copy,
for(std::unique_ptr<Kind> t : store)
I cannot move it like
for(std::unique_ptr<Kind> &&t : store)
Then how do I do it ?
#include <iostream>
#include <vector>
struct Kind{
char a;
char *array;
Kind(const char c): a(c)
{
}
~Kind(){
free(array); // internal custom deallocator.
}
};
int main() {
std::vector<std::unique_ptr<Kind>> store;
store.push_back(std::make_unique<Kind>('y'));
store.push_back(std::make_unique<Kind>('z'));
for(std::unique_ptr<Kind> &t : store){
// increase size of Kind.array.
std::cout << t->a;
// Use the Kind.array
// clean up t automatically.
}
return 0;
}
Example of moving the element out of the vector.
int main() {
std::vector<std::unique_ptr<Kind>> store;
store.push_back(std::make_unique<Kind>('y'));
for(std::unique_ptr<Kind> &t : store){
auto tmp = std::move(t); // leaving a valid but empty entry in store
std::cout << tmp->a;
// clean up t automatically.
// tmp runs out of scope and cleans up
}
return 0;
}
In effect not much different from the reset, but might be relevant for what you actually do in your real program.
How to take ownership of an object while looping over std::vector of std::unique_ptr using a range based for loop?
Loop with a reference to the element, and std::move the unique pointer into another. Example:
for(std::unique_ptr<Kind> &t : store){
std::unique_ptr<Kind> owner = std::move(t);
// do something with newly owned pointer
I want to clean up
there's no need to keep older structs around
You could deallocate the object by resetting the pointer:
for(std::unique_ptr<Kind> &t : store) {
// do something
t.reset();
That said, this is typically unnecessary. They will be automatically be destroyed when the vector goes out of scope.
I'm trying to save some memory here
If you allocate dynamic objects while iterating this may be useful. Otherwise it won't affect peak memory use.
If you want to make sure the instances are deleted immediately after each iteration and you cannot wait until the entire loop is done, you can write a wrapper that takes care of that and expresses your intent at the same time:
template <typename T>
struct Stealing {
std::unique_ptr<T> ptr;
Stealing(std::unique_ptr<T>& ptr) : ptr(std::move(ptr)) {
}
auto operator*() {
return ptr.operator*();
}
auto operator->() {
return ptr.operator->();
}
}
You can use that in the loop as a drop-in replacement for a unique_ptr as such:
for (Stealing<Kind> t: store) {
// do what you like with t as if it was a std::unique_ptr
// when t goes out of scope, so does its member -> Kind gets destroyed
}

Create new struct, insert into list, re-use pointer, return in vector... whether and how to delete?

In C++ code that I wrote to demonstrate an algorithm in an answer, I'm creating structs in a function using new, storing them in a list, moving them to a vector, then returning the vector:
struct my_struct {int a, b, c;};
std::vector<my_struct> myFunction(...) {
std::list<my_struct> my_list;
std::list<my_struct>::iterator current = my_list.begin();
std::vector<my_struct> my_vector;
my_struct *new_struct = nullptr;
while (...) {
...
if (!new_struct) {
new_struct = new my_struct;
new_struct->a = ...
}
...
if (new_struct) {
new_struct->b = ...
my_list.insert(current, *my_struct);
my_struct = nullptr;
}
...
if (...) {
current->c = ...
my_vector.push_back(*current);
current = my_list.erase(current);
}
...
}
return my_vector;
}
It compiles and seems to work correctly, however I'm more used to JavaScript and this code just feels like translated JavaScript; I'm specifically wondering whether I'm creating memory leaks, and whether I have to delete the structs in the calling function (and how).
Yes, you have a memory leak. If you invoke the new command, you will need to invoke a delete command in the future to free the memory allocated by new.
So, in this statement:
my_list.insert(current, *my_struct);
you are indeed copy the contents of *my_struct, not getting the ownership of it. So, in the following statement:
my_struct = nullptr;
You just got a memory leak.
To solve this, change your design to use smartpointer, for example, unique_ptr, or, better yet, dont use pointer at all, and just use a plain object:
my_struct new_struct;
As others in the question section have already pointed out, you probably shouldn't use new at all. The only reason to use pointers there at all is the if(newstruct) checks, if they are an essential part of your algorithm.
But if you use new, you should delete, too. It's safe to do that after inserting the struct into the list or vector - the list and vector contain copies.
Beginning with C++17, std::optional (and before that, boost::optional) is a sensible alternative solution for your specific problem here. It removes the need for pointers and the danger of memory leaks but at the same time still gives you a "nothing" state.
Your pseudo code would become something like:
// this is the correct way of defining a struct in C++:
struct my_struct {
int a;
int b;
int c;
};
std::vector<my_struct> myFunction(...) {
std::list<my_struct> my_list;
std::list<my_struct>::iterator current = my_list.begin();
std::vector<my_struct> my_vector;
std::optional<my_struct> new_struct; // new_struct does not hold a value
while (...) {
...
if (!new_struct.has_value()) { // if it does not hold a value...
new_struct = my_struct(); // it holds a value now (a default my_struct)
new_struct->a = ... // access syntax like a pointer
}
...
if (new_struct.has_value()) {
new_struct->b = ...
my_list.insert(current, *new_struct); // dereference syntax like a pointer
new_struct.reset(); // it no longer holds a value now
}
...
if (...) {
current->c = ...
my_vector.push_back(*current);
current = my_list.erase(current);
}
...
}
return my_vector;
}
Note how the syntax of std::optional deliberately mimics that of pointers.

Use constructor to allocate memory

I have a class that contains several arrays whose sizes can be determined by parameters to its constructor. My problem is that instances of this class have sizes that can't be determined at compile time, and I don't know how to tell a new method at run time how big I need my object to be. Each object will be of a fixed size, but different instances may be different sizes.
There are several ways around the problem:- use a factory- use a placement constructor- allocate arrays in the constructor and store pointers to them in my object.
I am adapting some legacy code from an old application written in C. In the original code, the program figures out how much memory will be needed for the entire object, calls malloc() for that amount, and proceeds to initialize the various fields.
For the C++ version, I'd like to be able to make a (fairly) normal constructor for my object. It will be a descendant of a parent class, and some of the code will be depending on polymorphism to call the right method. Other classes descended from the same parent have sizes known at compile time, and thus present no problem.
I'd like to avoid some of the special considerations necessary when using placement new, and I'd like to be able to delete the objects in a normal way.
I'd like to avoid carrying pointers within the body of my object, partially to avoid ownership problems associated with copying the object, and partially because I would like to re-use as much of the existing C code as possible. If ownership were the only issue, I could probably just use shared pointers and not worry.
Here's a very trimmed-down version of the C code that creates the objects:
typedef struct
{
int controls;
int coords;
} myobject;
myobject* create_obj(int controls, int coords)
{
size_t size = sizeof(myobject) + (controls + coords*2) * sizeof(double);
char* mem = malloc(size);
myobject* p = (myobject *) mem;
p->controls = controls;
p->coords = coords;
return p;
}
The arrays within the object maintain a fixed size of the life of the object. In the code above, memory following the structure of myobject will be used to hold the array elements.
I feel like I may be missing something obvious. Is there some way that I don't know about to write a (fairly) normal constructor in C++ but be able to tell it how much memory the object will require at run time, without resorting to a "placement new" scenario?
How about a pragmatic approach: keep the structure as is (if compatibility with C is important) and wrap it into a c++ class?
typedef struct
{
int controls;
int coords;
} myobject;
myobject* create_obj(int controls, int coords);
void dispose_obj(myobject* obj);
class MyObject
{
public:
MyObject(int controls, int coords) {_data = create_obj(controls, coords);}
~MyObject() {dispose_obj(_data);}
const myobject* data() const
{
return _data;
}
myobject* data()
{
return _data;
}
int controls() const {return _data->controls;}
int coords() const {return _data->coords;}
double* array() { return (double*)(_data+1); }
private:
myobject* _data;
}
While I understand the desire to limit the changes to the existing C code, it would be better to do it correctly now rather than fight with bugs in the future. I suggest the following structure and changes to your code to deal with it (which I suspect would mostly be pulling out code that calculates offsets).
struct spots
{
double x;
double y;
};
struct myobject
{
std::vector<double> m_controls;
std::vector<spots> m_coordinates;
myobject( int controls, int coordinates ) :
m_controls( controls ),
m_coordinates( coordinates )
{ }
};
To maintain the semantics of the original code, where the struct and array are in a single contigious block of memory, you can simply replace malloc(size) with new char[size] instead:
myobject* create_obj(int controls, int coords)
{
size_t size = sizeof(myobject) + (controls + coords*2) * sizeof(double);
char* mem = new char[size];
myobject* p = new(mem) myobject;
p->controls = controls;
p->coords = coords;
return p;
}
You will have to use a type-cast when freeing the memory with delete[], though:
myobject *p = create_obj(...);
...
p->~myobject();
delete[] (char*) p;
In this case, I would suggest wrapping that logic in another function:
void free_obj(myobject *p)
{
p->~myobject();
delete[] (char*) p;
}
myobject *p = create_obj(...);
...
free_obj(p);
That being said, if you are allowed to, it would be better to re-write the code to follow C++ semantics instead, eg:
struct myobject
{
int controls;
int coords;
std::vector<double> values;
myobject(int acontrols, int acoords) :
controls(acontrols),
coords(acoords),
values(acontrols + acoords*2)
{
}
};
And then you can do this:
std::unique_ptr<myobject> p = std::make_unique<myobject>(...); // C++14
...
std::unique_ptr<myobject> p(new myobject(...)); // C++11
...
std::auto_ptr<myobject> p(new myobject(...)); // pre C++11
...
New Answer (given comment from OP):
Allocate a std::vector<byte> of the correct size. The array allocated to back the vector will be contiguous memory. This vector size can be calculated and the vector will manage your memory correctly. You will still need to be very careful about how you manage your access to that byte array obviously, but you can use iterators and the like at least (if you want).
By the way here is a little template thing I use to move along byte blobs with a little more grace (note this has aliasing issues as pointed out by Sergey in the comments below, I'm leaving it here because it seems to be a good example of what not to do... :-) ) :
template<typename T>
T readFromBuf(byte*& ptr) {
T * const p = reinterpret_cast<T*>(ptr);
ptr += sizeof(T);
return *p;
}
Old Answer:
As the comments suggest, you can easily use a std::vector to do what you want. Also I would like to make another suggestion.
size_t size = sizeof(myobject) + (controls + coords*2) * sizeof(double);
The above line of code suggests to me that you have some "hidden structure" in your code. Your myobject struct has two int values from which you are calculating the size of what you actually need. What you actually need is this:
struct ControlCoord {
double control;
std::pair<double, double> coordinate;
};
std::vector<ControlCoord>> controlCoords;
When the comments finally scheded some light on the actual requirements, the solution would be following:
allocate a buffer large enough to hold your object and the array
use placement new in the beginning of the buffer
Here is how:
class myobject {
myobject(int controls, int coords) : controls(controls), coords(coords) {}
~myobject() {};
public:
const int controls;
const int coords;
static myobject* create(int controls, int coords) {
std::unique_ptr<char> buffer = new char[sizeof(myobject) + (controls + coords*2) * sizeof(double)];
myobject obj* = new (buffer.get()) myobject(controls, coords);
buffer.release();
return obj;
}
void dispose() {
~myobject();
char* p = (char*)this;
delete[] p;
}
};
myobject *p = myobject::create(...);
...
p->dispose();
(or suitably wrapped inside deleter for smart pointer)

How to strip away vector container and return an array?

When reading in files, it's convenient to allocate the memory via a vector:
someType* readCSV() {
std::vector<someType> vec;
someType x;
...
while(fscanf(f, parser, &x) != EOF) {
vec.push_back(x);
getc(f); // skip comma
}
return &vec[0];
}
But I just want to return an normal array (I'm working with CUDA afterwards whose API uses pointers).
So the question is whether vec going out of scope at the end of the function call will destroy the data it contains, and if there is anything I can do preserve it.
You cannot allocate memory in a function and not loosing it without the need to clean it up afterwards.
You could wrap the function into a class which stores the vector. Then you are able to return the pointer and the data will persist.
class csvReader
{
public:
csvReader (void) {}
type* readCSV (void)
{
type x;
while(fscanf(f, parser, &x) != EOF) {
vec.push_back(x);
getc(f); // skip comma
}
return vec.data();
}
private:
std::vector<type> vec;
};
Yes, according to how you declared it then the vector is allocated on stack hence the reference you return will become invalid when going out of scope.
You can have many solutions:
pass a vector to the function so that the caller is responsible for its allocation and deallocation
use a dynamic array (like someType *array = new someType[vec.size()] and you will be responsible of deallocating it through delete[] array
returning the vector itself so that it is pushed onto the stack and not deallocated upon exiting the function (return vec)

Self-registering global object

I am working on a library where users should be able to use static global instances. These instances (being run before main) register themselves in another global vector which can then be used...
Currently, it goes somewhat like this...
class A;
std::vector<A*> v;
class A {
public:
A (int i) : i(i) {
v.push_back(this);
}
int get () const {
return this->i;
}
private:
int i;
};
A a(1);
A b(2);
int main ()
{
for (A* const& c : v)
std::cout << c->get() << std::endl;
for (std::vector<A*>::iterator i = v.begin(); i != v.end(); i++)
delete *i;
return 0;
}
However, I'm afraid this code will leak... even more so when I don't want users to explicitely delete the contents of the vector (they'll forget it anyway), it should happen automatically at the end of main.
Are there other solutions? I wanted to use a vector of std::unique_ptr, but apparently they don't work that way...
Your code doesn't leak. The only thing that allocates memory there is std::vector, and it cleans itself up on destruction.
a and b are correctly destroyed and released at the end of execution.
You shouldn't delete things that weren't allocated with new.
Also, you are relying on v being initialised before a and b are constructed. You should lazily initialise v instead (see below).
std::vector<A*>& global_v()
{
static std::vector<A*> v;
return v;
}
// use global_v() instead of v in the A constructor.
To get what you want, just remove the loop that deletes those objects.
Here's your code running in action with the loops removed and some debug output added. Notice that both objects are destroyed correctly.