-3

I have a struct, which contains a few vectors, defined as follows:

#include <vector>
using namespace std;

struct data{
    vector<float> x;
    vector<float> y;
    vector<float> z;
}

Which I later use as such:

data d;
for(int i; i<3; i++){
    d.x.push_back(i)
    d.y.push_back(i*2)
    d.z.push_back(i*3)
}

And now I want to safely delete data in a way the completely deallocates all of the memory associated with it. I think that the way to do this is to write a simple destructor which clears and deallocates each field of data, and then delete the object:

struct data{
    vector<float> x;
    vector<float> y;
    vector<float> z;

    ~data(){
        vector<tempObject>().swap(x);
        vector<tempObject>().swap(y);
        vector<tempObject>().swap(z);
    }
}

and then this should work:

data d;
    for(int i; i<3; i++){
        d.x.push_back(i)
        d.y.push_back(i*2)
        d.z.push_back(i*3)
    }
delete data;

where I've made use to the top answer here to deallocate the vectors.

Will this work? If not, can you describe why and/or suggest an alternative? I understand that the memory will be freed once d leaves scope, but I need to free the memory before that happens.

pretzlstyle
  • 2,774
  • 5
  • 23
  • 40
  • 1
    You never have to worry about cleaning up `std::vector`'s memory unless you go out of your way to provide a bad allocator. – François Andrieux Apr 23 '19 at 19:49
  • 1
    no need for delete, since you have "data d" as stack object. vector (as most other stl containers take care of cleanup for you). if you use modern c++ and manage your heap objects on shared_ptr or unique_ptr, you (almost) never need to use the keywords new and delete – skeller Apr 23 '19 at 19:49
  • `delete data;` makes no sense. –  Apr 23 '19 at 19:49
  • @FrançoisAndrieux What would be a bad allocator? – pretzlstyle Apr 23 '19 at 19:49
  • 1
    You only `delete` what you `new`ed. You didn't `new` anything so don't `delete` anything. – François Andrieux Apr 23 '19 at 19:49
  • When the `data` object goes out of scope it will release all of its resources. That said, the OS may not recover it until the program ends. What actual problem are you trying to solve? – NathanOliver Apr 23 '19 at 19:51
  • @FrançoisAndrieux hmm... might you suggest an alternative, then? I need to free the memory that is used by `data` – pretzlstyle Apr 23 '19 at 19:51
  • @Anonymous You can provide `std::vector` with more than 1 template argument. This allows you to provide a type that controls how it's memory is managed. You don't do that here, you'll probably never need to do that. It's not applicable in the case of `std::vector`. – François Andrieux Apr 23 '19 at 19:51
  • @Anonymous Don't do anything and the memory will automatically be taken care of. That's the magic of standard containers and automatic storage. When `d` leaves scope it's gone and cleaned up for you. Edit : The linked answer is about freeing the vector's memory when it won't be destroyed right away but you want to make sure it's memory is released right now. – François Andrieux Apr 23 '19 at 19:51
  • Well, that's an explicit way to do it. If you do nothing instead, the vector destructors will be called and will free the memory used inside of the container. BTW calling delete on a stack allocated object is nonsense. – ppetraki Apr 23 '19 at 19:52
  • @NathanOliver Yes, but I need to free the memory allocated by `data` and it's members before it goes out of scope – pretzlstyle Apr 23 '19 at 19:53
  • Code shown is not C++, not clear what you want to do – Slava Apr 23 '19 at 19:53
  • The first half of your question was right. Get rid of all the stuff where you tried to clean up memory, because you're doing it wrong, and you never needed to in the first place. – Kenny Ostrom Apr 23 '19 at 19:53
  • @Anonymous Can you show an example? Normally you just need to scope the variable correctly to get the behavior you want. – NathanOliver Apr 23 '19 at 19:53
  • "but I need to free the memory allocated by data and it's members before it goes out of scope" then use `std::unique_ptr` and call reset when you need to clear the memory – Slava Apr 23 '19 at 19:54
  • You can't reduce the capacity of a vector, but you can replace r with a new instance, which may have the vectors at their minimal capacity. – Kenny Ostrom Apr 23 '19 at 19:57
  • @Slava Could you make an answer that elaborates? – pretzlstyle Apr 23 '19 at 19:57
  • @KennyOstrom Why do you think that I don't need to do it? – pretzlstyle Apr 23 '19 at 19:59
  • If you want dynamic memory management, that's a tutorial question, and you need to learn c++ from a good book. You need to be able to correctly ask the question to be on topic here. There's good reason -- if you just get a code snippet you don't understand, out of context, from stack overflow, you'll have unmaintainable code and not learn it. – Kenny Ostrom Apr 23 '19 at 20:01

3 Answers3

1

When the struct is destroyed its members will be destroyed (in reverse order of declaration). The vectors being thus destroyed will clean up their own memory.

No need for a custom destructor.

Jesper Juhl
  • 30,449
  • 3
  • 47
  • 70
  • And how do I properly destroy the `struct` `d`? Also, is your second sentence really true? The discussion at the SO question linked to in my question suggests otherwise. – pretzlstyle Apr 23 '19 at 19:57
  • 1
    @Anonymous When `d` goes out of scope, it no longer exists. The same is true of the `vector`'s inside `d`. – David Schwartz Apr 23 '19 at 20:06
  • "And how do I properly destroy the struct d?" - in the code you showed, `d` will be automatically destroyed when it goes out of scope - at the `}`. And yes, it *is* true that destroying a `std::vector` will free its memory - whether or not your implementation then chooses to hold on to that memory to use for future allocations or give it back to the OS is another matter entirely. As is what the OS chooses to do with memory that the impletation chooses to give back. That's *not* something C++ concerns itself with. – Jesper Juhl Apr 23 '19 at 20:07
1

And now I want to safely delete data in a way the completely deallocates all of the memory associated with it.

In C++ there are variables with automatic, static and dynamic storage duration. Lifetime of automatic storage duration that you have in your example and static one is controlled by compiler, so you cannot change their lifetime (small exception is prolongation of rvalue by reference, but that is unrelated here). If you need to manually control lifetime you need to create a variable with dynamic storage duration:

auto d = std::make_unique<data>();
d->x.push_back(1.0);
...
d.reset(); // terminate of lifetime of variable pointed by d manually
Slava
  • 43,454
  • 1
  • 47
  • 90
0

no need for delete, since you have "data d" as stack object.

vector (as most other stl containers take care of cleanup for you).

you also do not need a custom destructor for the struct

if you use modern c++ and manage your heap objects on shared_ptr or unique_ptr, you (almost) never need to use the keywords new and delete.

example:

#include <vector>
#include <memory>

struct MyData
{
    std::vector<float> x;
    std::vector<float> y;
    std::vector<float> z;
};

int main()
{
    //example 1: stack object
    {
        MyData d;
        for(int i = 0; i<3; i++)
        {
            d.x.push_back(i);
            d.y.push_back(i*2);
            d.z.push_back(i*3);
        }
    } // scope of d ends, everything including the vectors are cleaned up


    //example 2: heap object  
    {
        std::unique_ptr<MyData> dataPtr = std::make_unique<MyData>();
        for(int i = 0; i<3; i++)
        {
            dataPtr->x.push_back(i);
            dataPtr->y.push_back(i*2);
            dataPtr->z.push_back(i*3);
        }
    } // scope of dataPtr ends, everything will be cleaned up

    //example 3: heap object, clean up within scope
    {
        std::unique_ptr<MyData> dataPtr = std::make_unique<MyData>();
        for(int i = 0; i<3; i++)
        {
            dataPtr->x.push_back(i);
            dataPtr->y.push_back(i*2);
            dataPtr->z.push_back(i*3);
        }

        dataPtr.reset(); // this will clean-up whatever the pointer points to

    } // scope of dataPtr ends, ptr itself is destoryed

}
skeller
  • 1,151
  • 6
  • 6
  • What if I want to clean up `d` before it leaves scope? Of course I could reorganize my code in such a way that this will happen, but it would mean moving around many hundreds of lines (currently, many new objects are declared between the point that `d` is created, and the point that I'd like it to be freed, and those objects are needed throughout the program) – pretzlstyle Apr 23 '19 at 20:00
  • @Anonymous What do you mean by "clean up" exactly? Since `d` is still in scope, it's still accessible. Do you want to have an invalid, garbage object in scope that would cause unpredictable behavior if accessed? Are you looking to save a little memory? (If so, just add a `clear` (or `reset`) function to the `struct` that empties all the vectors and call that function. The object will still be valid, but the vectors will be empty.) – David Schwartz Apr 23 '19 at 20:05
  • @DavidSchwartz I'm looking to save a ton of memory, to be more accurate. The contents of `d` is >100TB, and it is moved after read-in to yet another struct to facilitate some MPI communication. In short, I use the struct `d` for read in only, and need to clear it after the data is copied elsewhere. Perhaps the best solution, though, is just to restructure the code so the scoping handles all this. – pretzlstyle Apr 23 '19 at 20:14
  • added example 3 for cleaup within scope. be aware that dereferencing the pointer after reset() will crash the program. – skeller Apr 23 '19 at 20:16
  • if you want to pass around the data, use the unique_ptr or a shared_ptr. that way you may save some copy operations. also consider in-place transformations when modifying the data. – skeller Apr 23 '19 at 20:19
  • @Anonymous Then just write a function to empty the vectors. Call it when you want to empty the vectors. – David Schwartz Apr 23 '19 at 20:43