I seem to have a little memory leak problem with vectors.
My code looks like this:
class CPart {
public:
virtual void print() = 0;
};
//some other classes
class CDisk : public CPart {
public:
CDisk(int tp, int size);
~CDisk();
virtual void print();
void AddPartition(int size, const string & dsc);
static const int MAGNETIC = 0;
static const int SDD = 1;
private:
struct CPartition {
CPartition(int size, const string & dsc);
int div_size;
string disk;
};
int type;
int d_size;
vector<CPartition> ptts;
};
CDisk::CDisk(int tp, int size) {
type = tp;
d_size = size;
}
CDisk::CPartition::CPartition(int size, const string& dsc) {
div_size = size;
disk = dsc;
}
void CDisk::AddPartition(int size, const string& dsc) {
ptts.push_back(CPartition(size, dsc));
}
int main(int argc, char** argv) {
CDisk disk(CDisk::SDD, 5000);
disk.AddPartition(500, "disk1");
CPart *disk2 = new CDisk(disk);
delete disk2;
return 0;
}
When I run this code with valgrind, it says there are memory leaks and the number of bytes lost is equal to the number of items in vector ptts * size of CPartition. So I am guessing I have to clean that vector somehow. I have tried that but to no avail.
You need to have virutal destructor in CPart
class CPart {
public:
virtual void print() = 0;
virtual ~CPart(){};
};
Otherwise you will get following scenario;
int main(int argc, char** argv) {
CDisk disk(CDisk::SDD, 5000);
disk.AddPartition(500, "disk1");
CPart *disk2 = new CDisk(disk);//CDisk created
delete disk2;//But here only CPart is deleted leaving CDisks data in memory
return 0;
}
You can use valgrind to very precisely isolate the origin of memory leaks by using additional leak check parameters, ie:
valgrind --leak-check=full ./a.out
As long as your code is compiled with debug symbols, valgrind will tell you exactly where the leak is coming from.
I dont think this part is really true;
struct CPartition {
CPartition(int size, const string & dsc);
int div_size;
string disk;
};
CDisk::CPartition::CPartition(int size, const string& dsc) {
div_size = size;
disk = dsc;
}
It is better to put struct CPartition out of your class definition and get rid of CDisk::CPartition::CPartition(int size, const string& dsc) i.e:
struct CPartition {
int div_size;
string disk;
};
To call div_size of an instance of CPartition you should do
instance_of_CPartition->div_size
For further, read structure tutorial.
I'm not sure if this will solve your question but this will solve another problem in your code.
Related
I have a scenario where I have multiple operations represented in the following way:
struct Op {
virtual void Run() = 0;
};
struct FooOp : public Op {
const std::vector<char> v;
const std::string s;
FooOp(const std::vector<char> &v, const std::string &s) : v(v), s(s) {}
void Run() { std::cout << "FooOp::Run" << '\n'; }
};
// (...)
My application works in several passes. In each pass, I want to create many of these operations and at the end of the pass I can discard them all at the same time. So I would like to preallocate some chunk of memory for these operations and allocate new operations from this memory. I came up with the following code:
class FooPool {
public:
FooPool(int size) {
foo_pool = new char[size * sizeof(FooOp)]; // what about FooOp alignment?
cur = 0;
}
~FooPool() { delete foo_pool; }
FooOp *New(const std::vector<char> &v, const std::string &s) {
return new (reinterpret_cast<FooOp*>(foo_pool) + cur) FooOp(v,s);
}
void Release() {
for (int i = 0; i < cur; ++i) {
(reinterpret_cast<FooOp*>(foo_pool)+i)->~FooOp();
}
cur = 0;
}
private:
char *foo_pool;
int cur;
};
This seems to work, but I'm pretty sure I need to take care somehow of the alignment of FooOp. Moreover, I'm not even sure this approach is viable since the operations are not PODs.
Is my approach flawed? (most likely)
What's a better way of doing this?
Is there a way to reclaim the existing memory using unique_ptrs?
Thanks!
I think this code will have similar performance characteristics without requiring you to mess around with placement new and aligned storage:
class FooPool {
public:
FooPool(int size) {
pool.reserve(size);
}
FooOp* New(const std::vector<char>& v, const std::string& s) {
pool.emplace_back(v, s); // in c++17: return pool.emplace_back etc. etc.
return &pool.back();
}
void Release() {
pool.clear();
}
private:
std::vector<FooOp> pool;
}
The key idea here being that your FooPool is essentially doing what std::vector does.
I'm starting to get a grasp on pointers and avoiding memory leaks...
I have one question though... Before I begin, I am NOT using C++11 so please don't reply with information on smart pointers and such that are specific to C++11...
I have the following code...
class Test
{
public:
Test(const int s_id, const std::string s_name) :
id(s_id),
name(s_name)
{
};
const int GetID()
{
return id;
}
private:
const int id;
const std::string name;
};
class TestCollection
{
public:
void AddTest(Test& my_test)
{
tests[my_test.GetID()] = &my_test;
}
void RemoveTest(const int id)
{
if (tests.find(id) != tests.end())
{
tests.erase(id);
}
}
public:
std::map<int, Test*> tests;
};
int _tmain(int argc, _TCHAR* argv[])
{
TestCollection collection;
Test my_test(0, "First Test");
collection.AddTest(my_test);
collection.RemoveTest(0);
return 0;
}
My question is do I need to do anything else to clear up the memory from my_test when I call RemoveTest? So as to avoid a memory leak?
I know that when I use the new keyword I need to call delete... But what do I do in this case?
Does it just get auto cleaned up by the garbage collector?
In the example both collection and my_test are allocated on the stack. As soon as the scope ends(return from _tmain) the memory will be released.
Taking pointers of stack variables that can exist outside the variable scope will result in unpredictable behavior. In this case if collection takes the object and stores the pointer rather than a copy.
I'm making a game with cocos2d-x. The different objects in the game i want to store in a class (I dont know if this is a good idea, but so i can give every object a lot of attributes). Then i make an array out of the objects and for that i need an own datastructure, where i can push and pop my objects. I tried to write this datastructure, but i think i doing wrong with my push function (i want to dynamically increase array size), especially the delete []? Doesn't that destroy my object-pointers stored?
ObjectArray.h:
#pragma once
#include "C:\Cocos\Projects\FirstGame\proj.win32\anObject.h"
class ObjectArrayList
{
public:
ObjectArrayList(int c);
ObjectArrayList();
virtual ~ObjectArrayList(void);
void push(anObject *obj);
void pop(int id);
int findIndex(int id);
int getSize();
int getCapacity();
private:
int capacity;
int size;
anObject **objectList;
};
ObjectArray.cpp:
#include "ObjectArrayList.h"
#include <iostream>
using namespace std;
objectArrayList::ObjectArrayList(int c)
{
size=0;
capacity = c;
objectList = new anObject*[capacity];
}
ObjectArrayList::ObjectArrayList() {
}
ObjectArrayList::~ObjectArrayList(void) {
}
void ObjectArrayList::push(anObject *obj) {
if(size < capacity) {
} else {
int newCap = 2*capacity;
anObject **tmpObjectList = new anObject*[newCap];
for(int i = 0;i<capacity;i++) {
tmpObjectList[i] = objectList[i];
}
delete [] objectList;
objectList = tmpObjectList;
capacity = newCap;
}
objectList[size] = obj;
size++;
}
void ObjectArrayList::pop(int id) { //not finish yet
if(size != 0) {
size--;
}
}
int ObjectArrayList::findIndex(int id) {
return id;
}
int ObjectArrayList::getSize() {
return size;
}
int ObjectArrayList::getCapacity() {
return capacity;
}
anObject.h:
#pragma once
#include "cocos2d.h"
class anObject
{
public:
anObject(int hp_init, int x, int y);
anObject();
virtual ~anObject(void);
void decreaseHp();
int getHp();
void setMyPosition(int x, int y);
cocos2d::Sprite *getMySprite();
private:
cocos2d::Sprite *mySprite;
int hp;
int midX;
int midY;
int isX;
int isY;
};
Bert
As the comments pointed out... you should save some time and energy and try to use the Standard Template Library (STL).
If you insist on fixing this code, I think you should try referencing objectlist after the delete to see if it's still there... maybe this assignment...
objectList = tmpObjectList;
...is not tolerated.
Instead... try to build a copy constructor "public Object(Object copiedObject){}", make a new Object*[] of the 2X size, populate it, then get rid of the old and... without deleting objectList assign your new Object*[] to it...
The rest seems fine to me... hope this helps.
delete [] objectList;
This only frees the array which objectList points to. It does not free any of the objects in that array.
I have class
Class A{
};
typedef struct
{
const char *dec_text;
void (A::*TestFun)();
} Test ;
Test _funs[] = {{"testLogOK", &A::testLogOK},
{"testLoginException", &A::testLoginException}
};;
How can i initialize this Test Array in construct method. The _funs tracks the A's method name and corresponding address, the methods which like:
void (methodName) (void)
In construction method, both below ways fail:
_funs = {{"testLogOK", &A::testLogOK},
{"testLoginException", &A::testLoginException}
};
The other question is how can i invoke the function pointer.. I tried the way like:
int
A::run (const char *name, int argc, ACE_TCHAR *argv[])
{
for(int i=0; i< sizeof(_funs)/sizeof(Test); i++){
Test test = _funs[i];
*(test.testFun)(); //this->*(test.fun)(); Both fail with same error
//(this->*(test.fun))() works
}
}
The compile also fails with message:
error C2064: term does not evaluate to a function taking 0 arguments
[UPdate]
I removed the struct Test and Test _funs out of Class A. But still have problem in A's method:
int A::run (const char *name, int argc, ACE_TCHAR *argv[])
The testLogOK and testLoginException method do exist as member functions of class A
Try this:
class A
{
public:
struct Test
{
const char *dec_text;
void (A::*TestFun)();
};
A(Test tt[])
{
for (int i=0; tt[i].dec_text; i++)
_funs[i] = tt[i];
}
void f1() { printf("this is f1\n"); }
void f2() { printf("this is f2\n"); }
void f3() { printf("this is f3\n"); }
Test _funs[100];
};
A::Test tt[] =
{
{ "Function f1", &A::f1},
{ "Function f2", &A::f2},
{ "Function f3", &A::f3},
{0, 0}
};
void test()
{
A a(tt);
(a.*(a._funs[0].TestFun))();
A *pa = new A(tt);
(pa->*(pa->_funs[1].TestFun))();
delete pa;
// EDIT: call f3
(a.*(tt[2].TestFun))(); // this will call directly from the global table
}
This will invoke the function assigned to the pointer.
This can be improved quite a bit if you typedef the pointer to the member
typedef void (A::*PF_T)();
and use a std::map as container:
std::map<std::string, PF_T> func_map;
It can be streamlined a lot more, but I hope it helps up to this point.
I defined a class in the header file like this:
class myClass
{
public:
void test();
void train();
private:
bool check;
}
Then in the cpp file, I did this:
void myClass::test()
{
int count = 9;
//some other work
}
void myClass::train()
{
int newValue = count;
....
}
Then without surprise, I got an error saying count is not defined. So what I want to do is in my train function use the count value that is defined in the test. Is there any good way to do this without using any additional dependencies? Thank you.
Well yes. That's called a member variable. Exactly like your bool check;.
Do
private:
bool check;
int count;
and then use it directly in your functions.
void myClass::test()
{
count = 9;
//Same as this->count = 9;
}
void myClass::train()
{
int newValue = count;
//Same as int newValue = this->count;
}
In your example, when method test finishes its work, count variable does not exist anymore, so there's no way of accessing it. You have to ensure, that its lifetime will be long enough to be accessed from another place. Making it a class field solves the problem (this is what class fields are for :)).
Do it this way:
class myClass
{
public:
void test();
void train();
private:
bool check;
int count; // <- here
}
and then
void myClass::test()
{
count = 9;
//some other work
}
But that's not the only solution. You can do it in another way, say:
class myClass
{
public:
int test()
{
// do some work
return 9;
}
void train(int count)
{
int newValue = count;
}
}
// (somewhere)
myClass c;
int count = c.test();
c.train(count);
That all depends on what test, train and count are for...