I found this memory leak from Valgrind which gave the memory error: Invalid free() / delete / delete[] / realloc().
==7367== Invalid free() / delete / delete[] / realloc()
==7367== at 0x4C2BDEC: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7367== by 0x40077F: ItemSet::~ItemSet() (cart.cpp:33)
==7367== by 0x40086B: ShoppingCart::~ShoppingCart() (cart.cpp:14)
==7367== by 0x400828: main (cart.cpp:45)
==7367== Address 0x5a1c0b0 is 0 bytes inside a block of size 40 free'd
==7367== at 0x4C2BDEC: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7367== by 0x40077F: ItemSet::~ItemSet() (cart.cpp:33)
==7367== by 0x400800: ShoppingCart::ShoppingCart() (cart.cpp:39)
==7367== by 0x400817: main (cart.cpp:43)
==7367==
==7367==
==7367== HEAP SUMMARY:
==7367== in use at exit: 40 bytes in 1 blocks
==7367== total heap usage: 2 allocs, 2 frees, 80 bytes allocated
==7367==
==7367== LEAK SUMMARY:
==7367== definitely lost: 40 bytes in 1 blocks
==7367== indirectly lost: 0 bytes in 0 blocks
==7367== possibly lost: 0 bytes in 0 blocks
==7367== still reachable: 0 bytes in 0 blocks
==7367== suppressed: 0 bytes in 0 blocks
==7367== Rerun with --leak-check=full to see details of leaked memory
==7367==
==7367== For counts of detected and suppressed errors, rerun with: -v
==7367== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Here is the code. Its a simplified version of my program, but it still has the problem I am having.
#include <cstdlib>
class ItemSet {
private:
int* items;
public:
ItemSet();
virtual ~ItemSet();
// ItemSet Methods...
};
class ShoppingCart {
private:
ItemSet items_in_cart;
public:
ShoppingCart();
// ShoppingCart methods...
};
ItemSet::ItemSet() {
// Constructor
int max_num_of_items = 10;
items = (int*)calloc(sizeof(int), max_num_of_items);
}
ItemSet::~ItemSet() {
// Destructor
if (NULL != items) {
// Frees the dynamically allocated register files
free(items);
}
}
ShoppingCart::ShoppingCart() {
// Constructor
items_in_cart = ItemSet();
}
int main() {
ShoppingCart cart = ShoppingCart();
return 0;
}
ShoppingCart::ShoppingCart() {
// Constructor
items_in_cart = ItemSet();
}
That last line can't possibly work. Right after the assignment, we have two ItemSet objects with the same value for items -- the temporary created on the right side and items_in_cart. When the second one is destroyed, you have a double free.
Use a sensible method of having a collection of objects like std::list, std::vector, or std::array. Otherwise, follow the rule of 3, rule of 5, or of zero.
Related
sorry to post this, but i have not found any discussion dealing with the feeling i have when reading valgrind results. What i see is part of a large code, so i've tried to simplify it as much as possible.I have a class (ClassA), that contains a pointer to a object of another class (ClassB). Both classes have a method named getArr that returns a double*. The one in ClassA basically returns a call to the one from ClassB through its pointer.
from what valgrind tells me, i've the feeling that ClassA is not really returning the pointer from its ClassB object but that it might copy it... Is is correct and if so how to avoid it ?
here is the header:
class ClassB
{
public:
ClassB(){}
~ClassB(){}
double *getArr();
};
class ClassA
{
public:
ClassA();
~ClassA();
double *getArr();
ClassB *myB;
};
the functions:
#include <iostream>
#include "OtherClasses.h"
using namespace std;
ClassA::ClassA()
{
myB = new ClassB();
}
ClassA::~ClassA()
{
if( myB )
delete myB;
}
double* ClassA::getArr()
{
return (myB->getArr());
}
double* ClassB::getArr()
{
double* arr = new double[10];
for(unsigned int i=0; i<10; i++)
arr[i]=i;
return arr;
}
int main(int argc, char *argv[])
{
ClassA *myA = new ClassA();
double* pouet = myA->getArr();
for(unsigned int i=0; i<10; i++)
cout<<pouet[i]<<endl;
delete[] pouet;
if (myA)
delete myA;
}
and what is displayed:
==2115== Memcheck, a memory error detector
==2115== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==2115== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==2115== Command: ./bin/main
==2115==
0
1
2
3
4
5
6
7
8
9
==2115==
==2115== HEAP SUMMARY:
==2115== in use at exit: 72,704 bytes in 1 blocks
==2115== total heap usage: 4 allocs, 3 frees, 72,793 bytes allocated
==2115==
==2115== 72,704 bytes in 1 blocks are still reachable in loss record 1 of 1
==2115== at 0x4A06C0F: malloc (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==2115== by 0x350388A1EF: ??? (in /usr/lib64/libstdc++.so.6.0.21)
==2115== by 0x34FD80F669: call_init.part.0 (in /usr/lib64/ld-2.21.so)
==2115== by 0x34FD80F77A: _dl_init (in /usr/lib64/ld-2.21.so)
==2115== by 0x34FD800CC9: ??? (in /usr/lib64/ld-2.21.so)
==2115==
==2115== LEAK SUMMARY:
==2115== definitely lost: 0 bytes in 0 blocks
==2115== indirectly lost: 0 bytes in 0 blocks
==2115== possibly lost: 0 bytes in 0 blocks
==2115== still reachable: 72,704 bytes in 1 blocks
==2115== suppressed: 0 bytes in 0 blocks
==2115==
==2115== For counts of detected and suppressed errors, rerun with: -v
==2115== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
thanks in advance
jbb
EDIT: As said in the comments the behaviour described above is consistent with valgrind 3.10 and 3.11 and using g++ 5.1, 5.3 and clang++... The only compilator that gives 3 alloc and 3 frees (so no problem at all) is g++ 4.8
#Sarthak Singh: Removing the delete myB in ClassA destructor brings these line in the output of valgrind
==23329== 1 bytes in 1 blocks are definitely lost in loss record 1 of 2
==23329== at 0x4A07117: operator new(unsigned long) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==23329== by 0x400A4C: ClassA::ClassA() (main.cpp:8)
==23329== by 0x400B2E: main (main.cpp:34)
it seems to me the leak is coming from libstdc++:
$> valgrind --leak-check=full --show-leak-kinds=all ./a.out
[...]
==6664== 72,704 bytes in 1 blocks are still reachable in loss record 1 of 1
==6664== at 0x4C2ABD0: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==6664== by 0x4EBFE7F: pool (eh_alloc.cc:117)
==6664== by 0x4EBFE7F: __static_initialization_and_destruction_0 (eh_alloc.cc:244)
==6664== by 0x4EBFE7F: _GLOBAL__sub_I_eh_alloc.cc (eh_alloc.cc:307)
==6664== by 0x400F3B9: call_init.part.0 (in /usr/lib/ld-2.23.so)
==6664== by 0x400F4CA: _dl_init (in /usr/lib/ld-2.23.so)
==6664== by 0x4000DC9: ??? (in /usr/lib/ld-2.23.so)
[...]
(which explains why the leak is only seen when using gcc-5.x)
it's either a real leak or some interplay b/w the libstdc++ version shipped with gcc-5.x and the hooks valgrind injects into the monitored process.
AFAIK, nothing much you can do about it.
Try removing the destructor of ClassB as delete just calls the destructor if it is defined.
You could read this for more info Delete calling destructor but not deleting object?
See the program below:
#include <cstdio>
#include <cstring>
#include <iostream>
class Chaine {
private:
char* _donnees;
unsigned int _taille;
public:
Chaine();
Chaine(const char*);
~Chaine();
unsigned int taille() const;
};
Chaine::Chaine():_taille(0) {
_donnees=new char[1];
_donnees[0]='\0';
}
Chaine::Chaine(const char *s) {
_taille = std::strlen(s);
_donnees = new char[_taille + 1];
std::strcpy(_donnees, s);
std::printf("%s(%d): %s\n", __FILE__, __LINE__, __func__);
}
Chaine::~Chaine() {
if(*_donnees == 0){
std::printf("_donnees points to freed block\n");
}
else{
std::printf("_donnees points to freed block\n");
delete[] _donnees;
_donnees=NULL;
}
std::printf("%s(%d): %s\n", __FILE__, __LINE__, __func__);
}
unsigned int Chaine::taille() const{
return _taille;
}
int main() {
Chaine s1("une chaine");
Chaine *s2 = new Chaine("s3");
Chaine s3 = s1;
delete s2;
}
I compiled using g++ -Wall -o test test.cpp then run valgrind --leak-check=full ./test and got messages below:
/test
==5638== Memcheck, a memory error detector
==5638== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==5638== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==5638== Command: ./test
==5638==
test.cpp(29): Chaine
test.cpp(29): Chaine
_donnees points to freed block
test.cpp(41): ~Chaine
_donnees points to freed block
test.cpp(41): ~Chaine
==5638== Invalid read of size 1
==5638== at 0x804886D: Chaine::~Chaine() (in /home/qliang/Documents/ENSEIRB/cpp/td2/chaine2/test)
==5638== by 0x804895F: main (in /home/qliang/Documents/ENSEIRB/cpp/td2/chaine2/test)
==5638== Address 0x4353028 is 0 bytes inside a block of size 11 free'd
==5638== at 0x402B598: operator delete[](void*) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==5638== by 0x80488A3: Chaine::~Chaine() (in /home/qliang/Documents/ENSEIRB/cpp/td2/chaine2/test)
==5638== by 0x8048953: main (in /home/qliang/Documents/ENSEIRB/cpp/td2/chaine2/test)
==5638==
_donnees points to freed block
==5638== Invalid free() / delete / delete[] / realloc()
==5638== at 0x402B598: operator delete[](void*) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==5638== by 0x80488A3: Chaine::~Chaine() (in /home/qliang/Documents/ENSEIRB/cpp/td2/chaine2/test)
==5638== by 0x804895F: main (in /home/qliang/Documents/ENSEIRB/cpp/td2/chaine2/test)
==5638== Address 0x4353028 is 0 bytes inside a block of size 11 free'd
==5638== at 0x402B598: operator delete[](void*) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==5638== by 0x80488A3: Chaine::~Chaine() (in /home/qliang/Documents/ENSEIRB/cpp/td2/chaine2/test)
==5638== by 0x8048953: main (in /home/qliang/Documents/ENSEIRB/cpp/td2/chaine2/test)
==5638==
test.cpp(41): ~Chaine
==5638==
==5638== HEAP SUMMARY:
==5638== in use at exit: 0 bytes in 0 blocks
==5638== total heap usage: 3 allocs, 4 frees, 22 bytes allocated
==5638==
==5638== All heap blocks were freed -- no leaks are possible
==5638==
==5638== For counts of detected and suppressed errors, rerun with: -v
==5638== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
I the deconstructor, I want to check if the memory _donnees points to has been freed to avoid re-free.
One solution(maybe bad solution) is to declare a static integer in deconstructor, like
Chaine::~Chaine() {
static int num_free = 0;
if(num_free == 1){
std::printf("_donnees points to freed block\n");
}
else{
std::printf("_donnees points to freed block\n");
delete[] _donnees;
num_free = 1;
_donnees=NULL;
}
std::printf("%s(%d): %s\n", __FILE__, __LINE__, __func__);
}
But I want to know if there is some way like *_donnees == NULL to check if the block of memory is freed or not.
And, why valgrind displays messages:
==5638== Invalid read of size 1
==5638== Invalid free() / delete / delete[] / realloc()
and why each of these messages just show once?
You are violating the Rule of Three. You should define a copy constructor and a copy assignment operator.
I'm resizing and array of objects. I made a temp object but when I don't delete it Valgrind shows memory leaks and an error. Deleting it causes a segfault. Just wondering what Valgrind is complaining about...
void Obj::resize()
{
Obj *temp = new Obj[size * 2]; //<-- line 92
for (int i = 0; i < size; i++)
temp[i] = objarray[i];
delete [] objarray;
objarray = temp;
size *= 2;
//delete temp; //<-- causes segfault
//delete [] temp; // also segfaults, tried them both just in case :\
}
Here's the Valgrind report:
==9292== HEAP SUMMARY:
==9292== in use at exit: 21,484 bytes in 799 blocks
==9292== total heap usage: 3,528 allocs, 2,729 frees, 91,789 bytes allocated
==9292==
==9292== 21,484 (2,644 direct, 18,840 indirect) bytes in 1 blocks are definitely lost in loss record 4 of 4
==9292== at 0x4008409: operator new[](unsigned int) (vg_replace_malloc.c:357)
==9292== by 0x804AC7E: MyClass::resize() (file.cpp:92)
==9292== by 0x804AC34: MyClass::add(int, int) (file.cpp:82)
==9292== by 0x804AAE6: getline(std::istream&, MyClass&) (file.cpp:66)
==9292== by 0x8049772: main (otherfile.cpp:39)
==9292==
==9292== LEAK SUMMARY:
==9292== definitely lost: 2,644 bytes in 1 blocks
==9292== indirectly lost: 18,840 bytes in 798 blocks
==9292== possibly lost: 0 bytes in 0 blocks
==9292== still reachable: 0 bytes in 0 blocks
==9292== suppressed: 0 bytes in 0 blocks
==9292==
==9292== For counts of detected and suppressed errors, rerun with: -v
==9292== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
I'm not too good with gdb, but got this backtrace:
(gdb) run
Starting program:
Program received signal SIGSEGV, Segmentation fault.
0x46ed40e3 in free () from /lib/libc.so.6
Missing separate debuginfos, use: debuginfo-install glibc-2.15-58.fc17.i686 libgcc-4.7.2-2.fc17.i686 libstdc++-4.7.2-2.fc17.i686
(gdb) backtrace
#0 0x46ed40e3 in free () from /lib/libc.so.6
#1 0x4742dba0 in operator delete(void*) () from /lib/libstdc++.so.6
#2 0x0804ad68 in MyClass::resize (this=0xbffff28c) at file.cpp:98
#3 0x0804ac35 in MyClass::add (this=0xbffff28c, month=10, day=31)
at file.cpp:82
#4 0x0804aae7 in getline (input=..., a=...) at file.cpp:66
#5 0x08049773 in main (argc=1, argv=0xbffff344) at otherfile.cpp:39
(gdb)
I think that deleting this is bad, because it should just leave the pointer dangling, so it doesn't surprise me that I get a segfault. Still, why would it then cause memory problems? Any ideas would be greatly appreciated.
Indeed, you can't delete it there since you've assigned it to objarray to be used later.
Most likely, you're not deleting objarray in the destructor; or some other function is reassigning it without deleting the old array first.
I would use std::vector rather than a hand-crafted array, to take care of deallocation for me.
If this is the SECOND (or later) time you call resize, then this is a very likely scenario, because you are trying to delete on a heap that has already had a double delete since the temp was already deleted, and now all your objArray writes have gone into a lump of memory that belongs to the heap-management, not to your code.
All sorts of other potential issues may also happen here, such as the memory is now being used for some OTHER object, and it's writing things into the heap memory that you then use as objArray.
You shouldn't delete temp where you are trying to do so. Just don't.
Explicit delete (or delete[]) should only be needed in very low-level library code. Everywhere else you should use smart pointers instead.
Here's a better approach that is (IMO) easier to understand:
std::unique_ptr<Obj[]> temp(new Obj[size * 2]);
// copy stuff from objarray to temp
swap(objarray, temp);
That's it. The unique_ptr destructor will free the old objarray buffer if the swap succeeded. And if an exception was thrown during the copy, it will free the new temporary buffer. In either case objarray (which should also be std::unique_ptr<Obj[]>) is left with a valid buffer.
I am currently implementing a basic garbage collector which purpose it is to delete all left dynamically allocated objects at the end of program. I hope the class documentation makes it more clear:
/**
* This basic garbage collector provides easy memory leak prevention.
* Just derive your class from utils::Object and the collector will
* care about freeing dynamically allocated objects. This basic
* implementation will just free all internal cached objects at the end
* of program. So allocated memory which was not freed manually will
* stay blocked up to this point.
*/
class GarbageCollector {
private:
// All object collector should care about (true means array)
std::map< Object*, bool > objects;
GarbageCollector();
/**
* Free left allocated memory.
*/
~GarbageCollector() {
std::map< Object*, bool >::iterator it = objects.begin();
int counter = 0;
while( it != objects.end() ) {
// save pointer and iterate to next because
// delete will remove obj from object set
Object* obj = it->first;
bool array = it->second;
++it;
++counter;
if( array ) {
delete[] obj;
}
else
delete obj;
}
if( counter )
std::cout << "GC: " << counter << " object(s) freed\n";
}
public:
/**
* #return Static collector instance.
*/
static GarbageCollector& getCollector();
void addObject( Object* obj );
void addArray( Object* obj );
void remove( Object* obj );
};
This base class Object from which other classes will inherit from will add the pointer of the allocated memory to this gc:
class Object {
public:
void* operator new( std::size_t size ) {
void* ptr = malloc( size );
if( !ptr )
throw std::bad_alloc();
GarbageCollector::getCollector().addObject( static_cast<Object*>(ptr) );
return ptr;
}
void operator delete( void* ptr ) {
GarbageCollector::getCollector().remove( static_cast<Object*>(ptr) );
free( ptr );
}
void* operator new[]( std::size_t size ) {
void* ptr = malloc( size );
if( !ptr )
throw std::bad_alloc();
GarbageCollector::getCollector().addArray( static_cast<Object*>(ptr) );
return ptr;
}
void operator delete[]( void* ptr ) {
GarbageCollector::getCollector().remove( static_cast<Object*>(ptr) );
free( ptr );
}
};
This works fine for the new statement. But if try to allocate an array via new[] the program crashes. Valgrind --leak-check=yes gives this output:
==3030== Invalid read of size 8
==3030== at 0x408305: utils::GarbageCollector::~GarbageCollector() (garbageCollector.cpp:40)
==3030== by 0x55A4820: __run_exit_handlers (exit.c:78)
==3030== by 0x55A48A4: exit (exit.c:100)
==3030== by 0x558A313: (below main) (libc-start.c:258)
==3030== Address 0x5b8e038 is 8 bytes before a block of size 144 alloc'd
==3030== at 0x4C28F9F: malloc (vg_replace_malloc.c:236)
==3030== by 0x409A59: utils::Object::operator new[](unsigned long) (object.cpp:45)
==3030== by 0x409B58: start() (main.cpp:49)
==3030== by 0x409C30: main (main.cpp:54)
==3030==
==3030== Invalid free() / delete / delete[]
==3030== at 0x4C282E0: free (vg_replace_malloc.c:366)
==3030== by 0x409AE8: utils::Object::operator delete[](void*) (object.cpp:54)
==3030== by 0x408339: utils::GarbageCollector::~GarbageCollector() (garbageCollector.cpp:40)
==3030== by 0x55A4820: __run_exit_handlers (exit.c:78)
==3030== by 0x55A48A4: exit (exit.c:100)
==3030== by 0x558A313: (below main) (libc-start.c:258)
==3030== Address 0x5b8e038 is 8 bytes before a block of size 144 alloc'd
==3030== at 0x4C28F9F: malloc (vg_replace_malloc.c:236)
==3030== by 0x409A59: utils::Object::operator new[](unsigned long) (object.cpp:45)
==3030== by 0x409B58: start() (main.cpp:49)
==3030== by 0x409C30: main (main.cpp:54)
==3030==
GC: 1 object(s) freed
==3030==
==3030== HEAP SUMMARY:
==3030== in use at exit: 144 bytes in 1 blocks
==3030== total heap usage: 8 allocs, 8 frees, 896 bytes allocated
==3030==
==3030== 144 bytes in 1 blocks are definitely lost in loss record 1 of 1
==3030== at 0x4C28F9F: malloc (vg_replace_malloc.c:236)
==3030== by 0x409A59: utils::Object::operator new[](unsigned long) (object.cpp:45)
==3030== by 0x409B58: start() (main.cpp:49)
==3030== by 0x409C30: main (main.cpp:54)
==3030==
==3030== LEAK SUMMARY:
==3030== definitely lost: 144 bytes in 1 blocks
==3030== indirectly lost: 0 bytes in 0 blocks
==3030== possibly lost: 0 bytes in 0 blocks
==3030== still reachable: 0 bytes in 0 blocks
==3030== suppressed: 0 bytes in 0 blocks
==3030==
==3030== For counts of detected and suppressed errors, rerun with: -v
==3030== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 4 from 4)
I debugged the program an the gc is trying to delete the memory at the adress which new[] returned. Can you tell me where my fault is?
You cannot use delete[] expression with a pointer returned from operator new[]. You must use operator delete[] directly.
This is because new[] expression sometimes adjusts the result of operator new[], and delete[] expression adjusts the argument in the opposite direction So:
If you have a pointer returned by a new[] expression, free it with a delete[] expression.
If you have a pointer returned by a call to operator new[], free it with a call to operator delete[].
In general, this is also true with respect to new expression/operator new/delete expression/operator delete, but GCC lets you get away with this.
This is a technical answer, concerning only the crash. The usefulness of the code as a memory leak prevention tool is discussed in comments.
Update A quick an dirty example of the thesis can be found at http://ideone.com/0atp5
Please note that if you call operator delete[] instead of delete[],
The destructors will not be called (but if you free all objects automatically, destructors are not needed anyway)
You do not need to cast pointers to Object* and back, just store everything as a void*.
GarbageCollector::~GarbageCollector() calls Object::operator[] delete and Object::operator delete, which change the GarbageCollector::objects map, while iterating over it. Try making a copy first:
...
std::map< Object*, bool > objectsCopy = objects;
std::map< Object*, bool >::iterator it = objectsCopy.begin();
int counter = 0;
while( it != objectsCopy.end() ) {
...
If you do this only at the end of the program, inhibit the remove() calls to not remove it at all. This object will be destroyed an instant later and the map will be empty regardless.
I'm trying to learn C++ and valgrind. So I wrote the following code to test it out. But I get some memory leaks. Can anyone explain what's causing the memory leak? Thanks in advance.
#include <vector>
#include <iostream>
using namespace std;
class test
{
int c;
public:
void whatever();
};
void test:: whatever()
{
vector<test*> a;
if(true)
{
test* b = new test();
b->c = 1;
a.push_back(b);
}
test* d = a.back();
cout << "prints: " << d->c;
delete d;
}
int main()
{
test* a = new test();
a->whatever();
return 1;
}
from valgrind
==28548== HEAP SUMMARY:
==28548== in use at exit: 4 bytes in 1 blocks
==28548== total heap usage: 3 allocs, 2 frees, 16 bytes allocated
==28548==
==28548== 4 bytes in 1 blocks are definitely lost in loss record 1 of 1
==28548== at 0x4C27CC1: operator new(unsigned long) (vg_replace_malloc.c:261)
==28548== by 0x400C36: main (in a.out)
==28548==
==28548== LEAK SUMMARY:
==28548== definitely lost: 4 bytes in 1 blocks
==28548== indirectly lost: 0 bytes in 0 blocks
==28548== possibly lost: 0 bytes in 0 blocks
==28548== still reachable: 0 bytes in 0 blocks
==28548== suppressed: 0 bytes in 0 blocks
==28548==
==28548== For counts of detected and suppressed errors, rerun with: -v
==28548== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 4 from 4)
Am I not allowed to delete from a copy of a pointer or am I doing something else wrong?
You never call delete on a.
Of course, the important bit here is that you are using a vector of pointers. Why in the world would you do this? Let the vector take care of memory management for you!
You forgot to delete a; at the end of main().
Note that everything you wrote should never go into real code. You should never use dynamic allocation (new) unless you absolutely have to and know precisely why.
Assuming you want to maintain the vector of pointers for educational purposes, then here's a better way of writing it:
#include <vector>
#include <memory> // for unique_ptr
// intentionally left blank; NO abusing namespace std!
struct Foo
{
int c;
void whatever()
{
std::vector<std::unique_ptr<test>> v;
if (true)
{
v.emplace_back(new test);
v.back()->c = 1;
}
// everything is cleaned up automagically
}
};
int main()
{
Test a; // automatic, not dynamic
a.whatever();
return 1;
}
This is still just for educational purposes; in real life you would try very hard to make do with a plain std::vector<test>, since vector is already a dynamic data structure and there is little need for the extra level of indirection.
The memory leak is in main. You are not deleting the allocated test object.