3

Given the class:

class A {
    Public:
        void foo() {
            static int i;
            i++;
        }
};

How would you change it to prevent i from changing between instances following this example:

A o1, o2, o3;
o1.foo(); // i = 1
o2.foo(); // i = 1
o3.foo(); // i = 1
o1.foo(); // i = 2

i.e. allocate memory for i on every instance.

EDIT:

Yes, you can add i as an instance variable, but what if you need these counters in various (independent) functions ? I am looking to limit the scope of the variable only to the function ("in member functions"). It would seem awkward to add variables such as i, c, counter, counter_2 to the class if you need various counters, would it not ?

  • 4
    .... that's what *instance* variables are for – StoryTeller - Unslander Monica Mar 07 '19 at 16:15
  • 1
    `static` variables are what you do when you *don't* want unique instances. If you want to preserve a state per-instance of a `class` then you need to store that state as a member of the `class`. – François Andrieux Mar 07 '19 at 16:17
  • 1
    Upvoted. This question is weird but not necessarily poor. – Bathsheba Mar 07 '19 at 16:18
  • Think about what would happen if this did work the way you'd like: The "static" variable inside the member would have to be stored in part of the object instance to be instance-specific, but in C++ you usually declare the class separately from the member implementations and the class declaration has to be enough to allow the compiler to calculate the size of the object. Since the "static" variable is declared inside a method and not in the class definition, its size is not known by code that can only see the definition. Therefore we have a contradiction and this cannot work that way. – Stu Mar 07 '19 at 16:23
  • Related: https://stackoverflow.com/questions/6223355/static-variables-in-member-functions – Ted Lyngmo Mar 07 '19 at 17:48
  • Regarding: _It would seem awkward to add variables such as i, c, counter, counter_2 to the class if you need various counters, would it not ?_ - In that case, perhaps your class is trying to do too much? How many (non-counter) member variables does it have? Should it be broken down in smaller classes? – Ted Lyngmo Mar 07 '19 at 17:57

2 Answers2

5
class A
{
public:
    int i = 0;
    void foo(){
        ++i;
    }
};

is the normal way: i is now a member variable of the class. Clearly you don't want to use static.

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

In circumstances where declaring data members become costly(need for sparse members that are not used so often), An instance indepent collection - normally an associative one - may come in handy. Knowing nothing more about the OP's intention, std::map family of classes can be used as first speculation. We need to have one counter per visited object in A::foo, but not for unvisited instances(i.e. A instances not calling A::foo). This was the the simplest first solution I came up with:

void A::foo(){
    static std::map<A*,std::size_t> i;
    ++i[this];
    //...
};

Upon call to std::map::operator[] on an object not in the map, the associated value is default constructed in a memory location already zeroed by the allocator( in short words 1st-timers are automatically initialized to 0).

Red.Wave
  • 2,790
  • 11
  • 17
  • @RamGhadiyaram progammers hate typing – Red.Wave Mar 08 '19 at 07:16
  • Have an upvote. This has an elegance to it which is particularly pertinent following the OP's edit. Consider `const A*` though as the key? Of course though the map could grow to be large if there are many instantiations of `A` and subsequent calls of `foo`. But that's fixable, although I'd imagine the overhead is comparable to the separate class members of the simpler approach. – Bathsheba Mar 08 '19 at 07:56
  • @Bathsheba agreed. But associative containers are intended to implement sparse matrices. Moreover I just imply the interface of 'std::map'. But again any similar approach is only useful when 'A::foo' is rarely used compared to number of 'A' instances – Red.Wave Mar 08 '19 at 08:53