Calling all Instances of an Object

Pages: 12
So I am wondering how I would go about calling a function for all instances of an object. I tried googling it, but all I saw was solutions like making an array of pointers to the objects. What if I don't know how many objects there will be? Isn't there an easier way?

Thank you,
Numeri
There's no magic way to access all instances of a class. If you want to do that, you'll need to maintain some kind of container (e.g. a vector) of all the instances you've created, and then iterate over that and call the method on each one.

If you want a nice tidy design, you could encapsulate the container in a new class of your own, say MyClassContainer (to contain instances of MyClass). You could create interface methods on that class that map to the methods on the objects contained within it. Those methods can then perform the iteration and method calls. E.g. if MyClass has a method MyClass::DoSomething(), you could create MyClassContainer::DoSomethingToAll() which would iterate over the instances and call MyClass::DoSomething() on each one.

Edit: You could also create a factory class, MyClassFactory, to create instances of MyClass. The factory class could then store the instances it creates in the MyClassContainer object.
Last edited on
> What if I don't know how many objects there will be?

Use a resizeable container. Preferably unordered_set<> or set<>.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>
#include <unordered_set>

struct A
{
    A() { objects.insert(this) ; /* ... */ }
    A( const A& ) : A() { /* ... */ }
    A( A&& ) : A() { /* ... */ }
    ~A() { /* ... */ objects.erase(this) ; }

    template< typename FN > static void for_each_instance( FN fn )
    { for( A* p : objects ) fn(p) ; }

    void foo( int i, char c )
    { std::cout << "A::foo( " << this << ", " << i << ", " << c << " )\n" ; }

    void bar( double d ) const { std::cout << "A::bar( " << d << " )\n" ; }

    static std::unordered_set<A*> objects ;
};

std::unordered_set<A*> A::objects ;

int main()
{
    std::size_t n ;
    std::cout << "how many? " && std::cin >> n ;
    while( n-- ) new A() ;

    A::for_each_instance( []( A* p ) { p->foo( 99, 'X' ) ; } ) ;
    A::for_each_instance( []( A* p ) { p->bar( 12.8 ) ; } ) ;
    // A::for_each_instance( []( A* p ) { delete p ; } ) ; // ??
}

http://ideone.com/HSl5Xd
Last edited on
Okay. Too bad there isn't a nice 'magic' way to do it! Thank you for the help!

Numeri
> Too bad there isn't a nice 'magic' way to do it!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <iostream>
#include <unordered_set>

template < typename T > struct magic
{
    magic() { objects.insert( static_cast<T*>(this) ) ; }
    magic( const magic& ) : magic() {}
    magic( magic&& ) : magic() {}
    ~magic() { objects.erase( static_cast<T*>(this) ) ; }

    template< typename FN > static void for_each_instance( FN fn )
    { for( T* p : objects ) fn(p) ; }

    static std::unordered_set<T*> objects ;
};

template < typename T > std::unordered_set<T*> magic<T>::objects ;

struct A : magic<A>
{
    void foo( int i, char c )
    { std::cout << "A::foo( " << this << ", " << i << ", " << c << " )\n" ; }
};

struct B : magic<B>
{
    void bar( double d ) const
    { std::cout << "B::bar( " << this << ", " << d << " )\n" ; }
};

int main()
{
    A one ;
    B two ;
    {
        A three = one ;
        B b[2] ;
        A::for_each_instance( []( A* p ) { p->foo( 99, 'X' ) ; } ) ;
        B::for_each_instance( []( B* p ) { p->bar( 12.8 ) ; } ) ;
    }
    std::cout << "------------------------\n" ;
    A::for_each_instance( []( A* p ) { p->foo( -7, 'Y' ) ; } ) ;
    B::for_each_instance( []( B* p ) { p->bar( 123.45 ) ; } ) ;
}

http://ideone.com/9Z2qNR
Well, by "magic" I meant a simple built-in way, not writing your own code to create and manage a collection of the objects. The template base-class idea is nice :)

This question hints at a few concepts worth noting. First, the idea of a collection, or container, as we often say in C++. Second, is the idea that each of the elements in the collection must conform to the same interface. (This also hints at polymorphism.) An interface can be enforced by inheriting from an abstract type containing pure virtual functions.

By conforming to a particular interface, you can perform operations on different objects uniformly (such as calling a function on each of them).
MikeyBoy wrote:
Well, by "magic" I meant a simple built-in way, not writing your own code to create and manage a collection of the objects.
There are multiple problems with this. What if some other code created an instance of that class and they didn't want you to call that function for their instance? How could that be avoided? You have to manage the objects you want to deal with yourself, and besides what would you be doing with the ones you create anyway?
There are multiple problems with this.

Well, yes. I never for a moment suggested that it would be a good thing. I was merely providing the OP with the information they were asking for.
My mistake, I thought that I was quoting the OP.
> What if some other code created an instance of that class
> and they didn't want you to call that function for their instance?
> How could that be avoided?

By leaving the choice to the code that creates the instance. Wasn't that obvious?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include <iostream>
#include <unordered_set>

template < typename T > struct magic
{
    magic() : enable_for_each_instance(false) {}

    magic( bool b ) : enable_for_each_instance(b)
    { if(b) objects.insert( static_cast<T*>(this) ) ; }

    magic( const magic& that ) : magic(that.enable_for_each_instance) {}

    magic( magic&& that ) : magic(that.enable_for_each_instance) {}

    ~magic() { if(enable_for_each_instance) objects.erase( static_cast<T*>(this) ) ; }

    template< typename FN > static void for_each_instance( FN fn )
    { for( T* p : objects ) fn(p) ; }

    const bool enable_for_each_instance ;
    private: static std::unordered_set<T*> objects ;
};

template < typename T > std::unordered_set<T*> magic<T>::objects ;

struct A : magic<A>
{
    explicit A( bool enable_magic = false ) : magic<A>(enable_magic) {}
    void foo( int i, char c )
    { std::cout << "A::foo( " << this << ", " << i << ", " << c << " )\n" ; }
};

struct B : magic<B>
{
    explicit B( bool enable_magic = false ) : magic<B>(enable_magic) {}
    void bar( double d ) const
    { std::cout << "B::bar( " << this << ", " << d << " )\n" ; }
};

int main()
{
    A one(true), x ;
    B two(true), y ;
    {
        A three = one ;
        B four, five = two ;
        A a[1000] ;
        B b[25] ;
        A::for_each_instance( []( A* p ) { p->foo( 99, 'X' ) ; } ) ;
        B::for_each_instance( []( B* p ) { p->bar( 12.8 ) ; } ) ;
    }
    std::cout << "------------------------\n" ;
    A::for_each_instance( []( A* p ) { p->foo( -7, 'Y' ) ; } ) ;
    B::for_each_instance( []( B* p ) { p->bar( 123.45 ) ; } ) ;
}

http://ideone.com/inxooR
And what if there are multiple different sets of code that want to independently call their group?
My mistake, I thought that I was quoting the OP.

No worries :)
> And what if there are multiple different sets of code that want to independently call their group?

Aw, c'mon. Do you need someone to hold your hand for every small step?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#include <iostream>
#include <unordered_set>
#include <memory>

template < typename T, typename TAG = void  > struct magic
{
    magic() { objects.insert( static_cast<T*>(this) ) ; }

    magic( const magic& that ) : magic() {}

    magic( magic&& that ) : magic() {}

    ~magic() { objects.erase( static_cast<T*>(this) ) ; }

    template< typename FN > static void for_each_instance( FN fn )
    { for( T* p : objects ) fn(p) ; }

    private: static std::unordered_set<T*> objects ;
};

template < typename T, typename TAG > std::unordered_set<T*> magic<T,TAG>::objects ;

template < typename T, typename TAG = void > struct tracked
                                              : T, magic< tracked<T,TAG>, TAG >
{
    template < typename ... ARGS > tracked( ARGS... args ) : T(args...) {}
};

struct A
{
    virtual ~A() {}
    void foo( int i, char c )
    { std::cout << "A::foo( " << this << ", " << i << ", " << c << " )\n" ; }
};

struct B
{
    B( int a = 0, double b = 0 ) {}
    virtual ~B() {}
    void bar( const char* cstr )
    { std::cout << "B::bar( " << this << ", " << cstr << " )\n" ; }
};

int main()
{
    A not_tracked[10] ;
    B also_not_tracked[20] ;

    std::unique_ptr<A> default_tracked( new tracked<A> ) ;
    std::unique_ptr<B> also_default_tracked( new tracked<B> ) ;

    struct my_objects {};
    A* my_tracked_A_objects = new tracked< A, my_objects >[2] ;
    tracked< B, my_objects > my_tracked_B_objects[3] { {1,2.3}, {4,5.6}, {7,8.9} } ;

    struct their_objects {};
    tracked< A, their_objects > their_tracked_A_objects[4] ;

    std::cout << "tracked A (default)\n-----------------------\n" ;
    tracked<A>::for_each_instance( []( A* pa ) { pa->foo( 1, 'x' ) ; } ) ;

    std::cout << "\ntracked A (my_objects)\n---------------------\n" ;
    tracked<A,my_objects>::for_each_instance( []( A* pa ) { pa->foo( 2, 'y' ) ; } ) ;

    std::cout << "\ntracked A (their_objects)\n--------------\n" ;
    tracked<A,their_objects>::for_each_instance( []( A* pa ) { pa->foo( 3, 'z' ) ; } ) ;

    std::cout << "\ntracked B (my_objects)\n--------------\n" ;
    tracked<B,my_objects>::for_each_instance( []( B* pb ) { pb->bar( "hello" ) ; } ) ;
}

http://ideone.com/tZty99
JLBorges wrote:
Aw, c'mon. Do you need someone to hold your hand for every small step?
No, I need someone to explain why we keep going for the harder solution instead of just having code maintain their own lists where they have full control over how the lists are maintained.
> I need someone to explain why we keep going for the harder solution
> instead of just having code maintain their own lists
> where they have full control over how the lists are maintained.

That someone isn't me.

In my experience, addressing a special case every time is a lot harder than special-casing only if the general case doesn't fit. The idea isn't original http://en.wikipedia.org/wiki/Inventor's_paradox
Up to now I thought you were being esoteric, but now it seems that you are serious - really? Everything I know says having a static class variable that keeps track of instances for other arbitrary code is wrong, the code should track the instances itself in the way it wants to. It's like asking the integer class to keep track of your various matrices for you - nobody does that. I think there is a disconnect in understanding somewhere here.
> Everything I know says having a static class variable that keeps track of instances for other arbitrary code is wrong.
> I think there is a disconnect in understanding somewhere here.

There is.

template < typename T, typename TAG > std::unordered_set<T*> magic<T,TAG>::objects ;
is not 'a static variable'. It is a different variable for each T, and for the same T, a different variable for each specific use-case (identified by the TAG).

On line 18, I see the keyword "static".
> On line 18, I see the keyword "static".

Now you see it on line 8.

template < typename T, typename TAG > std::unordered_set<T*> magic<T,TAG>::objects ;
is not 'a static variable'. It is a different variable for each T, and for the same T, a different variable for each specific use-case (identified by the TAG).

Objects are tracked on a per use case basis.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <iostream>
#include <unordered_set>
#include <memory>

template < typename T, typename TAG = void  > struct magic
{
    // ...
    /* private: */ static std::unordered_set<T*> objects ;
};

template < typename T, typename TAG > std::unordered_set<T*> magic<T,TAG>::objects ;

template < typename T, typename TAG = void > struct tracked
                                              : T, magic< tracked<T,TAG>, TAG >
{
    template < typename ... ARGS > tracked( ARGS... args ) : T(args...) {}
};

struct A { /* ... */ };

template < int N > struct use_case {} ;

int main()
{
    std::cout << std::addressof( tracked<A>::objects ) << '\n' ;
    std::cout << std::addressof( tracked< A, use_case<1> >::objects ) << '\n' ;
    std::cout << std::addressof( tracked< A, use_case<2> >::objects ) << '\n' ;
    std::cout << std::addressof( tracked< A, use_case<3> >::objects ) << '\n' ;
    std::cout << std::addressof( tracked< A, use_case<4> >::objects ) << '\n' ;
    std::cout << std::addressof( tracked< A, use_case<5> >::objects ) << '\n' ;
}

http://ideone.com/1M0VDy
Last edited on
Pages: 12