What is the best way to count the total number of objects created in both stack and heap for different classes. I know that in C++ new and delete operators can be overloaded and hence in the default constructor and destructor the object count can be incremented or decremented as and when the objects get created or destroyed.
Further if i am to extend the same thing for object counting of objects of different classes, then i can create a dummy class and write the object count code in that class and then when i create any new class i can derive it from the Dummy class.
Is there any other optimal solution to the same problem.
then i can create a dummy class and write the object count code in that class and then when i create any new class i can derive it from the Dummy class.
Yes, but since each class needs its own count, you have to make a base class template and use the curiously recurring template pattern (CRTP):
template <class Derived>
class InstanceCounter
{
static int count;
protected:
InstanceCounter()
{
++count;
}
~InstanceCounter()
{
--count;
}
public:
static int instance_count()
{
return count;
}
};
template <class Derived>
int InstanceCounter<Derived>::count = 0;
class Test : public InstanceCounter<Test>
{
};
int main()
{
Test x;
std::cout << Test::instance_count() << std::endl;
{
Test y;
Test z;
std::cout << Test::instance_count() << std::endl;
}
std::cout << Test::instance_count() << std::endl;
}
The way the object is created in stack and heap is different.
The new operator is used create an object in heap, and normal object declaration will create an object in stack.
So by overloading an new operator we can count the object created in heap.
static variable can be used to count the objects.
To find the no of objects created on Heap and Stack. To create the object on the heap we use new so override the new and delete keywords to keep track of the counter.
class Test
{
static int heapcount;
static int stackcount;
public:
static int GetHeapCount()
{
return heapcount;
}
static int GetStackCount()
{
//The objects which are created on heap also will call constructor and increment the stack count, so remove the objects that are created on heap to get stack count
return stackcount - heapcount;
}
Test()
{
++stackcount;
}
~Test()
{
--stackcount;
}
void* operator new(size_t size)
{
++heapcount;
void * p = malloc(sizeof(Test));
return p;
}
void operator delete(void* p)
{
--heapcount;
free(p);
}
void operator=(Test const& obj)
{
int x = 0;
}
};
int Test::heapcount = 0;
int Test::stackcount = 0;
int main()
{
{
Test t;
Test t2;
Test* t1 = new Test();
std::cout << "HeapCount = " << Test::GetHeapCount() << std::endl;//HeapCount = 1 (t1)
std::cout << "StackCount = " << Test::GetStackCount() << std::endl;//StackCount = 2 (t,t2)
delete t1;
}
//As all the objects are deleted so count must be zero, stack objects will be removed when goes out of scope
std::cout << "HeapCount = " << Test::GetHeapCount() << std::endl;//HeapCount = 0
std::cout << "StackCount = " << Test::GetStackCount() << std::endl;//StackCount=0
{
Test t[3];
Test* t2 = new Test();
Test* t3 = new Test();
std::cout << "HeapCount = " << Test::GetHeapCount() << std::endl;//HeapCount = 2 (t2,t3)
std::cout << "StackCount = " << Test::GetStackCount() << std::endl;//StackCount = 3 (t[3])
}
//Two heap objects are not deleted, but stack objects has been cleaned
std::cout << "HeapCount = " << Test::GetHeapCount() << std::endl;//HeapCount = 2
std::cout << "StackCount = " << Test::GetStackCount() << std::endl;//StackCount = 0
}
Related
I have written below program to count the number of static and dynamically created object of the class.
#include <iostream>
class Test
{
public:
Test()
{
stackCount++;
}
void* operator new(size_t objSize)
{
void* ptr = malloc(objSize);
heapCount++;
return ptr;
}
static void Display()
{
std::cout << "stack object count : " << stackCount - heapCount << ", Heap object Count :" <<
heapCount << std::endl;
}
private:
static int stackCount;
static int heapCount;
};
int Test::stackCount = 0;
int Test::heapCount = 0;
int main()
{
Test obj1;
Test obj2;
Test obj3;
Test *ptr = new Test();
Test::Display();
return 0;
}
Program output : stack object count : 3, Heap object Count :1
is there any better way to maintain the count of static and dynamic object.?
void ZMDAggregator::getMZMap(DataModel::MZMap &mZM)
{
LOGGER_EVENT("ZMDAggregator getMZMap()");
std::unique_lock<std::mutex> lockSlot(internalStateMutex);
mZM.clear();
mZM = this->mZM;
}
void ZMDAggregator::Roscallback(const ros::MZMap msgMZMap)
{
std::unique_lock<std::mutex> lockSlot(internalStateMutex);
MZMap map;
for( auto const & entry : msgMZMap.m_z_e)
{
mzEntry.clear();
mzEntry.mID = entry.mID;
mzEntry.tMode = entry.tMode;
mzEntry.areaID = entry.areaID;
mzEntry.oZone = entry.oZone;
mzEntry.authZ = entry.authZ;
mzEntry.blockZ = entry.blockZ;
map.mzEntry.push_back(mzEntry);
}
}
The above function gets called around 30 times a second.This is causing a high cpu utilization in my program.
struct MZEntry
{
uint32_t mID;
bool tMode;
uint32_t areaID;
uint32_t oZone;
using ZList = std::vector<uint32_t>;
ZList authZ;
ZList blockZ;
};
struct MZMap
{
std::vector<MZEntry> mzEntry;
}
Class ZMDAggregator {
mutable std::mutex internalStateMutex;
MZMap mzMap;
}
My question is if I convert getMZMap() to accept a shared_ptr instead of a reference and also change the type of the member variable mzMap to a shared_ptr as shown below.
void ZMDAggregator::getMZMap(std::shared_ptr<DataModel::MZMap> &mZM)
{
LOGGER_EVENT("ZMDAggregator getMZMap()");
std::unique_lock<std::mutex> lockSlot(internalStateMutex);
mZM = this->mZM;
}
Class ZMDAggregator {
mutable std::mutex internalStateMutex;
std::shared_ptr<DataModel::MZMap> mzMap;
}
My question is as follows.
My class ZMDAggregator updates the structure once every 50 milliseconds, so around 20 times a second As you can see this happens inside the unique_lock.
The Thread that calls, getMZMap() calls it around 20 times a second.
By modifying initial structure to a shared_ptr, I should be able to bring down CPU cycles, as a struct copy is now avoided. However now since the same pointer is being accessed in the caller thread (Reader)
there is a risk that I can get half an old pointer and half a new pointer when the function Roscallback updates the structure.
Without using a mutex, (These two functions are two separate classes) is there a way to ensure that the above scenario doesn't occour ?
As per the suggestion of #freakish, I have returned shared_ptr by value. Please find the code below.
#include <iostream>
#include <memory>
#include <vector>
struct MZEntry
{
uint32_t mID;
bool tMode;
uint32_t areaID;
uint32_t oZone;
using ZList = std::vector<uint32_t>;
ZList authZ;
ZList blockZ;
};
struct MZMap
{
std::vector<MZEntry> mzEntry;
};
class A
{
public:
void populate()
{
std::cout << "A populate()" << std::endl;
MZEntry mzEntry;
mzEntry.mID = 55;
mzEntry.tMode = true;
mzEntry.areaID = 55;
mzEntry.oZone = 55;
mzEntry.authZ = {1,2,3};
mzEntry.blockZ = {4,5,6};
l->mzEntry.push_back(mzEntry);
}
std::shared_ptr<MZMap> assign() const
{
return l;
}
std::shared_ptr<MZMap> l;
A()
{
std::cout << "A constructor()" << std::endl;
l = std::make_shared<MZMap>();
populate();
}
};
class B
{
public:
B()
{
std::cout << "B constructor" << std::endl;
a = new A();
}
void getValue()
{
std::cout << "B getValue()" << std::endl;
p3 = a->assign();
}
void print()
{
std::cout << "machineID: " << p3->mzEntry[0].mID << std::endl;
}
std::shared_ptr<MZMap> p3;
A *a;
};
int main() {
B *b = new B();
b->getValue();
b->print();
return 0;
}
So what you are saying is in the line
p3 = a->assign();
It doesn't do a struct copy, instead it just increments the reference count? Is my understanding correct?
Currently I'm learning about classes and constructors. Yesterday I uploaded almost the same code, but with a different question. I needed to know something about delegation.
In my code 2 really strange things happen. In the main block I create object x that is part of the container class. When I try to output the lenght I get as ouput 33, which is ofcourse not true or at least not intended.
Maybe I should start another post for this, but it might be highly related. I also wrote in the main:
Container x1 = x;
std::cout << x1.GetData()[2] << std::endl;
std::cout << x1.GetLenght() << std::endl;
I tried to make a deep copy of x to x1. When I do .GetData() it shows really really small values (I think machine error) so that would indicate that the copy failed, but when I try to get the length the initial wrong output of 33.
This may be a bit messy, but due to covid I'm not able to ask the course instructors. Any feedback or material to think about would be highly appreciated.
Questions:
Why do I get as output that the length of object x (and indirect x1)is 33 ?
Why did the deepcopy fail to copy the elements?
Code:
Class:
class Container
{
public: //[DO NOT MODIFY/REMOVE THESE GETTERS AND SETTERS: THEY ARE USED IN THE SPECTEST]
int GetLength() const {return length;}
double* GetData() const {return data;}
void SetLength(const int length) {this->length = length;}
void SetData(double* data) {this->data = data;}
public:
// constructors
Container(){
length = 0;
data = nullptr;
}
Container(int len){
int length = len;
data = new double[length];
}
Container(std::initializer_list<double> il): Container(il.size())
{
std::copy(il.begin(), il.end(), data);
}
Container(const Container& other) : Container(other.length)
{
for (auto i=0; i<other.length; i++){
data[i] = other.data[i];
}
}
// destructor
~Container()
{
delete[] data;
length = 0;
}
// operators
void print(const std::string& info) const
{
// print the address of this instance, the attributes `length` and
// `data` and the `info` string
std::cout << " " << this << " " << length << " " << data << " "
<< info << std::endl;
}
private:
int length;
double* data;
};
Main:
int main()
{
Container x({1,2,4,5});
std::cout << "x has address " << &x << std::endl;
Container x1 = x;
std::cout << x1.GetData()[2] << std::endl;
return 0;
}
int length = len; doesn't modify member but creates a local variable. it should simply be:
length = len;
or better, use initializer list:
Container(int len) :
length{len},
data{new double[length]}
{
}
This question already has answers here:
Do Pointer Parameters Need To Be Passed By Reference
(3 answers)
Closed 3 years ago.
Object made using new operator does not seem to be available outside the scope! Isn't that the whole point of the new operator?
https://ideone.com/DDvo9y - Please check this link to see the result.
#include<iostream>
class myClass
{
private:
int val;
public:
myClass () = delete;
myClass (int val):val{val}{}
int get () const
{
return val;
}
};
bool ifEqualMake (int a, int b, myClass * obj)
{
if (a == b) obj = new myClass (a);
else{
std::cout << "Difference exists: " << a - b << '\n';
obj = new myClass (a + b);
}
std::cout << " Object made with value :" << obj->get () << '\n';
return (a == b);
}
int main ()
{
myClass *obj1 = nullptr;
myClass *obj2 = nullptr;
myClass *obj3 = nullptr;
ifEqualMake (3, 3, obj1);
ifEqualMake (4, 3, obj2);
ifEqualMake (4, 4, obj3);
if(obj1) std::cout << "obj 1 made in heap: " << obj1->get () << '\n';
if(obj2) std::cout << "obj 2 made in heap: " << obj2->get()<<'\n';
if(obj3) std::cout << "obj 3 made in heap: " << obj3->get () << '\n';
delete obj1;
delete obj2;
delete obj3;
return 0;
}
It isn't.
You're confusing the dynamically-allocated object that you created with new, and the pointer that points to it.
The pointer's scope is limited just like any other automatic-storage-duration object.
It looks like you meant to use it as an "out" argument to the function ifEqualMake, perhaps by taking a reference to it rather than a copy. Then alterations to it, such as pointing it to a new object, will be mirrored in the calling scope.
The parameter obj is passed by value, that means it's just a copy of the argument, and any modification on itself inside the function (like obj = new myClass (a);) has nothing to do with the original pointer. In the meanwhile, the object constructed inside the function won't be destroyed.
You might change it to pass-by-reference.
bool
ifEqualMake (int a, int b, myClass *& obj)
// ^
{
...
}
Consider the following function:
void foo(int i) {
i = 4;
}
void bar() {
int j = 0;
foo(j);
std::cout << j << '\n';
}
You would expect bar to print 0, not 4, because foo is assigning to a local variable.
This behaviour does not change with pointers. The following code behaves the same way:
void foo(int* i) {
int temp = 0;
i = &temp;
}
void bar() {
int* j = nullptr;
foo(j);
std::cout << j << '\n';
}
The simplest fix to the code you present is to take the pointer by reference:
void foo(int*& i) {
int temp = 0;
i = &temp;
}
void bar() {
int* j = nullptr;
foo(j);
// j now points to a destroyed object
std::cout << j << '\n';
}
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
My first question is: I am having a lot of trouble figuring out why the Example class is being constructed greater than the others. Below is a short app using a Template counter to track how many times the constructor/destructor/copy constructor is called for each class. There are a total of three classes: Example, Deep, Child. Each has a copy constructor... ugh.
Also, my second question, is what would be the correct way to define the copy constructor for the Child class?
In the printStatus(), it displays:
COUNTERS::NEW_COUNTER = 60
COUNTERS::DELETE_COUNTER = 50
COUNTERS::CONSTRUCTOR_COUNTER = 90
COUNTERS::DESTRUCTOR_COUNTER = 80
Example count = 10
Deep count = 0
Child count = 0
#include <iostream>
#include <vector>
#include <string>
using namespace std;
class COUNTERS
{
public:
static int NEW_COUNTER;
static int DELETE_COUNTER;
static int CONSTRUCTOR_COUNTER;
static int DESTRUCTOR_COUNTER;
};
int COUNTERS::NEW_COUNTER = 0;
int COUNTERS::DELETE_COUNTER = 0;
int COUNTERS::CONSTRUCTOR_COUNTER = 0;
int COUNTERS::DESTRUCTOR_COUNTER = 0;
/* template used for counting constructors/destructors to debug memory leaks */
template <typename T>
class Countable
{
static unsigned cs_count_;
public:
Countable() { ++cs_count_; }
Countable( Countable const& ) { ++cs_count_; }
virtual ~Countable() { --cs_count_;}
static unsigned count() { return cs_count_; }
};
template <typename T>
unsigned Countable<T>::cs_count_ = 0;
class Example : public Countable<Example>
{
public:
string a;
int b;
Example() {
COUNTERS::CONSTRUCTOR_COUNTER++;
a = "exampleString";
b = 5;
}
virtual ~Example() {
COUNTERS::DESTRUCTOR_COUNTER++;
}
// copy constructor
Example(const Example& e) {
COUNTERS::CONSTRUCTOR_COUNTER++;
this->a = e.a;
this->b = e.b;
}
};
class Deep : public Countable<Deep>
{
public:
int a;
string b;
Example* e;
Deep()
{
COUNTERS::CONSTRUCTOR_COUNTER++;
a = 3;
b = "deepString";
e = new Example();
COUNTERS::NEW_COUNTER++;
}
virtual ~Deep() {
if(e != NULL) {
delete e;
COUNTERS::DELETE_COUNTER++;
}
COUNTERS::DESTRUCTOR_COUNTER++;
}
// copy constructor
Deep(const Deep& x)
{
COUNTERS::CONSTRUCTOR_COUNTER++;
this->a = x.a;
this->b = x.b;
this->e = new Example();
COUNTERS::NEW_COUNTER++;
this->e->a = x.e->a;
this->e->b = x.e->b;
};
};
class Child : public Countable<Child>
{
public:
Deep d;
string name;
int age;
Example* e;
vector<Example> list;
vector<Deep> deep_list;
void init()
{
Deep* var = new Deep(); COUNTERS::NEW_COUNTER++;
deep_list.push_back(*var);
delete var; COUNTERS::DELETE_COUNTER++;
}
Child() {
COUNTERS::CONSTRUCTOR_COUNTER++;
name = "a";
age = 10;
d.a = 1;
d.b = "deep";
d.e = NULL;
e = new Example();
COUNTERS::NEW_COUNTER++;
list.push_back(*e);
init();
}
virtual ~Child() {
COUNTERS::DESTRUCTOR_COUNTER++;
if(e != NULL) {
delete e;
COUNTERS::DELETE_COUNTER++;
}
}
// copy constructor
Child(const Child& c)
{
}
};
void myChildFunction(){
Child* c = new Child();
COUNTERS::NEW_COUNTER++;
delete c;
COUNTERS::DELETE_COUNTER++;
}
void printStatus(){
cout << "COUNTERS::NEW_COUNTER = " << COUNTERS::NEW_COUNTER << endl;
cout << "COUNTERS::DELETE_COUNTER = " << COUNTERS::DELETE_COUNTER << endl;
cout << "COUNTERS::CONSTRUCTOR_COUNTER = " << COUNTERS::CONSTRUCTOR_COUNTER << endl;
cout << "COUNTERS::DESTRUCTOR_COUNTER = " << COUNTERS::DESTRUCTOR_COUNTER << endl;
cout << "Example count = " << Example::count() << endl;
cout << "Deep count = " << Deep::count() << endl;
cout << "Child count = " << Child::count() << endl;
}
int main()
{
for(unsigned int i=0 ; i < 10; i++)
myChildFunction();
printStatus();
return 0;
}
You are missing out on deleting some Example objects because of this line:
d.e = NULL;
in Child::Child().
You are allocating memory for e in the constructor of Deep. After executing the above line, that memory is leaked.
You can resolve that problem by:
Removing that line (or commenting it out),
Deleting d.e before making it NULL, or
Doing something else that prevents the memory leak.
Update, in response to comment
Copy constructor for Child:
Child(const Child& c) : d(c.d),
name(c.name),
age(c.age),
e(new Example(*c.e)),
list(c.list),
deep_list(c.deep_list)
{
COUNTERS::DESTRUCTOR_COUNTER++; // This is for Child
COUNTERS::NEW_COUNTER++; // This is for new Example
}
I removed all information that cluttered your code.
When using templates, constructors and copy constructors NEED the following: Example < eltType >(void);
in the class definition. All objects that inherit from Countables are known as derived classes. They also may call a derived class a child, and the class in which it is derived from is called the parent. I added the COPY_CONSTRUCTOR_COUNT to add clarification to the data which is being presented on the console/command prompt. Usually when trying to preform a task, large or small, doing it incrementally and by providing methods, for each task, saves you time and a headache. I removed the new_count and delete_count from the equation, because I felt that it was not needed.
You will notice that I added : Countable( * ((Countable < eltType > *)&e))
This is a requirement when designing a program that involves inheritance, which introduces the
topic of Polymorphism :D
What that bit of code does is that it gets a pointer of a Countable, which will point to the address of object e, which then allows access to all super classes of this class, but not including e's class.
NOTE: Since e is a derived class of Countable, this is valid statement.
For you second question, all of your data members are public, you can use an iterator to copy your data stored in you vectors.
As a concern from one programmer to another, I hope your code in practice is well documented, and all methods declared in your class are defined in a .cpp file.
#include <iostream>
#include <vector>
#include <string>
using namespace std;
class COUNTERS
{
public:
static int NEW_COUNTER;
static int DELETE_COUNTER;
static int CONSTRUCTOR_COUNTER;
static int DESTRUCTOR_COUNTER;
static int COPY_CONSTRUCTOR_COUNTER;
};
int COUNTERS::NEW_COUNTER = 0;
int COUNTERS::DELETE_COUNTER = 0;
int COUNTERS::CONSTRUCTOR_COUNTER = 0;
int COUNTERS::DESTRUCTOR_COUNTER = 0;
int COUNTERS::COPY_CONSTRUCTOR_COUNTER = 0;
/* template used for counting constructors/destructors to debug memory leaks */
template <typename T>
class Countable
{
public:
Countable<T>()
{
incrementObjectCount();
};
Countable<T>(Countable const&)
{
incrementObjectCount();
};
virtual ~Countable()
{
decrementObjectCount();
};
static unsigned count()
{
return cs_count_;
};
protected:
static unsigned cs_count_;
////////////////////////////////////ADDED////////////////////////////////////
protected:
void incrementObjectCount(void){ ++cs_count_; };
void decrementObjectCount(void){ --cs_count_; };
void incrementDeconstructorCounter(void){ ++COUNTERS::DESTRUCTOR_COUNTER; };
/////////////////////////////////////ADDED////////////////////////////////////
};
template <typename T>
unsigned Countable<T>::cs_count_ = 0;
class Example : public Countable<Example>
{
public:
Example() : Countable<Example>()
{
COUNTERS::CONSTRUCTOR_COUNTER++;
}
virtual ~Example()
{
incrementDeconstructorCounter();
}
// copy constructor
Example(const Example& e) : Countable<Example>(*((Countable<Example>*)&e))
{
// COUNTERS::CONSTRUCTOR_COUNTER++; This is copy constructor, you addmitted this from "Child" class CCstr
++COUNTERS::COPY_CONSTRUCTOR_COUNTER; // For even more information added this
}
};
class Deep : public Countable<Deep>
{
public:
Deep() : Countable<Deep>()
{
COUNTERS::CONSTRUCTOR_COUNTER++;
}
virtual ~Deep()
{
COUNTERS::DESTRUCTOR_COUNTER++;
}
// copy constructor
Deep(const Deep& x) : Countable<Deep>(*((Countable<Deep>*)&x))
{
//COUNTERS::CONSTRUCTOR_COUNTER++;
++COUNTERS::COPY_CONSTRUCTOR_COUNTER; // For even more information added this
};
};
class Child : public Countable<Child>
{
public:
vector<Example> list;
vector<Deep> deep_list;
void init()
{
deep_list.push_back(Deep());
list.push_back(Example());
}
Child() : Countable<Child>()
{
COUNTERS::CONSTRUCTOR_COUNTER++;
init();
}
virtual ~Child()
{
COUNTERS::DESTRUCTOR_COUNTER++;
}
// copy constructor
Child(const Child& c) : Countable<Child>(*((Countable<Child>*)&c))
{
++COUNTERS::COPY_CONSTRUCTOR_COUNTER; // For even more information added this
}
};
void myChildFunction(){
Child* c = new Child();
//COUNTERS::NEW_COUNTER++;not needed
delete c;
//COUNTERS::DELETE_COUNTER++; not need
}
void printStatus(){
cout << "COUNTERS::NEW_COUNTER = " << COUNTERS::NEW_COUNTER << endl;
cout << "COUNTERS::DELETE_COUNTER = " << COUNTERS::DELETE_COUNTER << endl;
cout << "COUNTERS::CONSTRUCTOR_COUNTER = " << COUNTERS::CONSTRUCTOR_COUNTER << endl;
cout << "COUNTERS::DESTRUCTOR_COUNTER = " << COUNTERS::DESTRUCTOR_COUNTER << endl;
cout << "COUNTERS::COPY_CONSTRUCTOR_COUNTER = " << COUNTERS::COPY_CONSTRUCTOR_COUNTER << endl;
cout << "Example count = " << Example::count() << endl;
cout << "Deep count = " << Deep::count() << endl;
cout << "Child count = " << Child::count() << endl;
}
int main()
{
for (unsigned int i = 0; i < 10; i++)
myChildFunction();
printStatus();
system("pause");
return 0;
}