1

I would like to count the number of objects that my program creates over its lifetime. Based on the solution provided here:

how to count the number of objects created in c++

I have the following code:

#include <iostream>
using namespace::std;
using std::cout;
using std::endl;

template <typename T>
struct counter
{
    counter()
    {
        objects_created++;
        objects_alive++;
    }

    virtual ~counter()
    {
        --objects_alive;
    }
    static int objects_created;
    static int objects_alive;
};
template <typename T> int counter<T>::objects_created(0);
template <typename T> int counter<T>::objects_alive(0);

class X : counter<X>
{
    int a;
};

class Y : counter<Y>
{
    int b;
};

void fooX(class X x) {
    cout << "passing object" << endl;
}

void fooY(class Y& y) {
    cout << "passing reference" << endl;
}

int main()
{
    cout << "created: " << " X:" << counter<X>::objects_created << " Y:" << counter<Y>::objects_created << endl;
    cout << "alive: " << " X:" << counter<X>::objects_alive << " Y:" << counter<Y>::objects_alive << endl;
    X x;
    Y y;
    cout << "created: " << " X:" << counter<X>::objects_created << " Y:" << counter<Y>::objects_created << endl;
    cout << "alive: " << " X:" << counter<X>::objects_alive << " Y:" << counter<Y>::objects_alive << endl;
    fooX(x);
    fooY(y);
    cout << "created: " << " X:" << counter<X>::objects_created << " Y:" << counter<Y>::objects_created << endl;
    cout << "alive: " << " X:" << counter<X>::objects_alive << " Y:" << counter<Y>::objects_alive << endl;
    int ui;
    cin >> ui;
}

I expected that since x is passed by value, a copy of it is made inside fooX making the total number of objects of class X to be 2 while since y is passed by reference, the total number of objects of class Y to be 1.

Yet, the output of the code is as follows:

created:  X:0 Y:0
alive:  X:0 Y:0
created:  X:1 Y:1
alive:  X:1 Y:1
passing object
passing reference
created:  X:1 Y:1
alive:  X:0 Y:1

Why does not the number of Xs created be 2?

Tryer
  • 3,580
  • 1
  • 26
  • 49
  • 3
    You forgot the copy constructor in the base class: `counter(T const &)` – Richard Critten Feb 15 '18 at 18:03
  • @RichardCritten I was under the mistaken understanding then that if the user does not provide one, the compiler automatically does. Let me try your suggestion. – Tryer Feb 15 '18 at 18:08
  • 2
    The compiler does provide one, but it may not do what you want. –  Feb 15 '18 at 18:09
  • 2
    The default copy constructor is really, really dumb. It does the absolute minimum to copy the data members (leading to much fun with pointers and other resources that require special handling. For more see [What Is the Rule Of Three?](https://stackoverflow.com/questions/4172722/what-is-the-rule-of-three)) and nothing more. It does not increment the counters, and it does not pass go and collect $200. – user4581301 Feb 15 '18 at 18:15
  • 1
    Also conciser what happens to the counters in the LHS object of `operator=` And don't forget Copy elision: http://en.cppreference.com/w/cpp/language/copy_elision – Richard Critten Feb 15 '18 at 20:03
  • @RichardCritten: I think assignment operator need not increment the counter since `X x1; X x2;...x1 = x2;` assignment already needs pre-existing objects where the counter would have been already incremented during object's initial creation. I have to think about elision but my code does not have such structures as of now. – Tryer Feb 16 '18 at 00:57
  • The default assignment operator is going overwrite the LHS counters with the values from the RHS, this is not what you want. So you need to implement the operator to not do this. – Richard Critten Feb 16 '18 at 01:00
  • hmm...but if x1 and x2 belong to the same class X, the counters being static are at the class level, so even if they are overridden, I think it should not be a problem. – Tryer Feb 16 '18 at 01:01

1 Answers1

2

A copy constructor is automatically added to your counter class, and that automatically created copy constructor doesn't increment your static variables.

Write a copy constructor which does that:

counter(counter const&)
{
    objects_created++;
    objects_alive++;
}

Note that your destructor should probably not be virtual, unless you intend to delete dynamically created instances of derived classes via pointers or references to counter. As it stands, it's just premature pessimisation because it needlessly increases the size of your objects.

Christian Hackl
  • 27,051
  • 3
  • 32
  • 62
  • I added `counter(T const & t) {objects_created++;objects_alive++;}` to the code above and reran, it still gives me the same result as I indicated in the OP. That is, the number of objects created of X is still shown to be 1 and not 2. – Tryer Feb 15 '18 at 18:13
  • @Tryer: That's because `counter(T const & t)` isn't a copy constructor. It's just a normal constructor taking a `T`, like `counter(int number)` or `counter(std::string const& text)`. – Christian Hackl Feb 15 '18 at 18:15
  • Yes. I changed that to the code you have in your answer and it works. Thank you! – Tryer Feb 15 '18 at 18:18