1

I want to allocate memory for a struct that contains std::vector. After allocating it, I will push_back some data to it. After all, I need to destroy my allocated struct. I want to know how can it be done with no memory corruption.

Here is my code:

typedef struct my_struct_t{

    int a, b;
    vector<unsigned> vec;

}
} MYSTRUCT;


int main(int argc, const char * argv[])
{

    MYSTRUCT* ptr_s =  new MYSTRUCT;

    for(int i = 0 ; i < 100 ; i++){
        ptr_s->vec.push_back(i);
    }
    ptr_s->vec.clear();
    delete ptr_s;

    return 0;
}

I tried to use clear as it is supposed to call destructor. But after valgrind-ing my code, there are still some blocks reachable. I also tried to deallocate vector using this:

vector<unsigned>().swap(ptr_s.vec)

But with no success.

output of `valgrind':

==52635== HEAP SUMMARY:
==52635==     in use at exit: 10,360 bytes in 5 blocks
==52635==   total heap usage: 147 allocs, 142 frees, 25,198 bytes allocated
==52635== 
==52635== LEAK SUMMARY:
==52635==    definitely lost: 0 bytes in 0 blocks
==52635==    indirectly lost: 0 bytes in 0 blocks
==52635==      possibly lost: 0 bytes in 0 blocks
==52635==    still reachable: 10,360 bytes in 5 blocks
==52635==         suppressed: 0 bytes in 0 blocks
==52635== Reachable blocks (those to which a pointer was found) are not shown.
==52635== To see them, rerun with: --leak-check=full --show-leak-kinds=all

Thank you everyone in advance.

update:

I noticed that the source of memory corruption in my application is in somewhere else. So I added an update. Here is the new code:

MYSTRUCT* ptr_s1 =  new MYSTRUCT;
MYSTRUCT* ptr_s2 =  new MYSTRUCT;

for(int i = 0 ; i < 100 ; i++){
    ptr_s1->vec.push_back(i);
}


memcpy(ptr_s2 , ptr_s1, sizeof(*ptr_s1));

delete ptr_s1;
delete ptr_s2;  // here I get seg fault

return 0;

As soon as deleting ptr_s2, seg fault happens.

Update: proper way, based on the accepted answer:

typedef struct my_struct_t{

    int a, b;
    vector<unsigned> vec;
    inline my_struct_t operator=(const my_struct_t &s ){
       a = s.a;
       b = s.b;
       vec = s.vec;
       return s;
    }
} MYSTRUCT;

MYSTRUCT* ptr_s1 =  new MYSTRUCT;
MYSTRUCT* ptr_s2 =  new MYSTRUCT;

for(int i = 0 ; i < 100 ; i++){
    ptr_s1->vec.push_back(i);
}

// no memcpy
// memcpy(ptr_s2 , ptr_s1, sizeof(*ptr_s1));
*ptr_s2 = *ptr_s1;

delete ptr_s1;
delete ptr_s2;  // no more sget seg fault

return 0;
Hamid Bazargani
  • 847
  • 1
  • 15
  • 30
  • 4
    Except for the C-ish uses of declaring a `struct` there are no memory leaks in your code. You also do not need to call `clear` if the vector will be destroyed anyway, nor need to dynamically allocate `my_struct_t`. – PaulMcKenzie Apr 16 '15 at 14:09
  • You can check this http://stackoverflow.com/questions/10464992/c-delete-vector-objects-free-memory – Zaksh Apr 16 '15 at 14:09
  • 1
    To truly test what you have, remove the `new MYSTRUCT` and just declare an instance of `MYSTRUCT`. Then you will see that there will be *no* dynamic memory being done by you, and everything is library code. If you still get the error, then it is either that valgrind has an issue, or the library code itself is the issue. – PaulMcKenzie Apr 16 '15 at 14:19
  • @PaulMcKenzie I added an update. – Hamid Bazargani Apr 16 '15 at 14:51
  • 1
    Do *not* use memcpy() for that struct. It contains a `std::vector`, therefore it is a non-POD type. Also, there is no need to define your own assignment operator. All the members in your struct are safely copyable (two ints and a vector) -- the compiler defined version is perfectly ok. – PaulMcKenzie Apr 16 '15 at 16:01

1 Answers1

9

You don't need to call std::vector::clear or do something else, the destructor will get called when you delete it via delete ptr_s;.

The still reachable matter is explained in Valgrind FAQ.

My program uses the C++ STL and string classes. Valgrind reports 'still reachable' memory leaks involving these classes at the exit of the program, but there should be none.

First of all: relax, it's probably not a bug, but a feature. Many implementations of the C++ standard libraries use their own memory pool allocators. Memory for quite a number of destructed objects is not immediately freed and given back to the OS, but kept in the pool(s) for later re-use. The fact that the pools are not freed at the exit of the program cause Valgrind to report this memory as still reachable. The behaviour not to free pools at the exit could be called a bug of the library though.

Update:

Briefly, don't copy classes with memcpy, if you use memcpy to copy a class object whose destructor deletes a pointer within itself (std::vector member in your case), you will end up with double delete when the second instance of the object is destroyed.

The right way is copy/move constructor and/or assignment operator for classes.

Alper
  • 12,860
  • 2
  • 31
  • 41