1

I want to wrap an operator function with overloading it for debug purposes.

E.g: I want to count how many = operation have been done during a program run for Foo object.

static int counter = 0;
Foo operator=(const Foo& b) 
{
    //Somehow call default functionality of = opreator for foo.

    counter++;
}

Is it possible to call just default functionality of operators when overloading them. Just like calling base function of overridden function when writing an overridden function.

Erkam D
  • 49
  • 6
  • What you need is a [CRTP](https://en.m.wikipedia.org/wiki/Curiously_recurring_template_pattern) class which counts assignments. I cannot provide you with the code right now, but this should be fairly easy... – jan.sende Jul 02 '19 at 12:05
  • I have tested a way. But it requires that your copy ctor exactly what copy assignment operator does (except counter++). – Gaurav Singh Jul 02 '19 at 12:08

4 Answers4

2

If by "default operator function" you mean you want the operator=() to do everything that would be achieved if you simply did

Foo &operator=(const Foo &) = default;

but, in addition, increment a counter, then there is no direct way, since such an operator can only have one definition.

However, you can achieve a similar effect by using something like

class Counter
{
     public:

          Counter &operator=(const Counter &) {++counter; return *this;};

          static int Count() {return counter;};
     private:
          static int counter;
};

and (in exactly one compilation unit that has visibility of the definition of class Counter e.g. by including the header that contains the class definition) do

int Counter::counter = 0;

Then simply add a single Counter as a private non-static member of your class Foo. That way, every usage of a "defaulted" operator=() in class Foo will increment the Counter::counter.

If your class Foo is the only place that a Counter is used, then the above will allow counting the number of times a Foo is assigned. All you need to do to obtain the count, at any time, is call Counter::Count().

As noted by Caleth in comments, the class Counter can be templated on the type, so a distinct counter for Foo versus other classes can be established. This also opens the door for using CRTP (the Curiously Recurring Template Pattern) in which Foo can derived from Counter<Foo> to provide the desired capability.

There are some potential caveats to be aware of;

  • The size of a Counter will be non-zero, so the size of a Foo will probably change.
  • You will need to ensure constructors and destructor of class Counter (however they are defined) work correctly with Foo;
  • The behaviour will be undefined if Counter::count ever overflows (which caps the number of times your class can be assigned);
  • There is nothing to stop other code from instantiating and assigning a Count, which will mess up your count (although that possibility might be mitigated (note I didn't say "countered") if Counter has all members private and specifies class Foo as a friend).
Peter
  • 35,646
  • 4
  • 32
  • 74
  • 1
    You can template `Counter` on a type, so that `Counter` has a distinct count to `Counter` – Caleth Jul 02 '19 at 13:14
  • It seems there is no way to do that I want. But, I liked the approach and it will be very useful in some cases I think. Thanks. – Erkam D Jul 02 '19 at 14:08
  • 1
    @Caleth - yes, that's true. When I think about it a bit more, it could be used as a base class as well (i.e. a form of CRTP) since the "default" `operator=()` for a class will take care of calling `operator=()` for bases. – Peter Jul 02 '19 at 14:30
1

If you provide a custom operator= implementation, the compiler doesn't generate the default one. There is no way to access it because it doesn't exist.

I suggest making a separate class with overloaded operator=, and adding it to class Foo as a field (or a base class).

HolyBlackCat
  • 78,603
  • 9
  • 131
  • 207
1

Here is an approach that introduces a template-based assignment operator, which will not overload the default one:

static int counter;
struct Foo
{
    template<bool=false> Foo& operator=(const Foo& b)
    {
        // The non-debug one
        return operator=(b);
    }
    template<> Foo& operator=<true>(const Foo& b)
    {
        // The debug one
        ++counter;
        return operator=(b);
    }
};

Then you can use

Foo f;
Foo g;
g.operator=<>(f); // This is the non-debug one
g.operator=<true>(f); // This is the non-debug one
g.operator=<false>(f); // This is the debug one

You can of course still write g = f.

Unfortunately though you can't, at the time of writing, write g=<false>f;, so the envisaged calling syntax is ugly.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
0

Note : This will work only if copy constructor does exactly what copy assignment operator is supposed to do (except incrementing static counter).

Foo operator=(const Foo& b) 
{
    ++counter;

    //Somehow call default functionality of = opreator for foo.
    Foo copy(b);
    return copy;

    //counter++;
}

You can check my code at onlinegdb.

I am not sure of other pitfalls in using this, than the one mentioned at top. Criticism is most welcome.

Gaurav Singh
  • 456
  • 6
  • 17