CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Page 1 of 2 12 LastLast
Results 1 to 15 of 27
  1. #1
    Join Date
    Nov 2009
    Posts
    18

    Question static function to call member function on all objects?

    Hello all,

    I'm working in Borland C++ Builder v6.0 (maintenance/rewriting some code). I have a class where I'd like to have a static function call a member function on all instantiated members of the class. (Motive: update all at once, where the update function only exists as a member of the base class.)

    The way I thought to do this was to have a vector of pointers to the class inside the class itself. Upon construction, each object would add its "this" pointer to the vector. Then on calling the static function, iterate through all pointers in the vector, calling the update function.

    It seems the linker doesn't like something about the vector, I get:
    "[Linker Error] Unresolved external 'MyClass::vec' referenced from PATH\FILENAME.OBJ"

    I was just trying a dummy class to prove it was doable. Am I doing something wrong? Or is this not possible? (If not, why not?)

    Code is below. Thanks.


    Code:
    #include <vcl.h>
    #include <vector>
    #pragma hdrstop
    
    using std::vector;
    
    //---------------------------------------------------------------------------
    
    class MyClass {
        public:
            MyClass();
        private:
            static vector<MyClass*> vec;
            int m;
    };
    
    MyClass::MyClass() {
        vec.push_back(this);
    }
    
    //---------------------------------------------------------------------------
    
    #pragma argsused
    int main(int argc, char* argv[])
    {
        MyClass mc;
    
        return 0;
    }

  2. #2
    Join Date
    Jan 2006
    Location
    Singapore
    Posts
    6,765

    Re: static function to call member function on all objects?

    You declared the vector, but never defined it. Define it in a source file. You probably need to have the destructor remove the object from the vector.
    C + C++ Compiler: MinGW port of GCC
    Build + Version Control System: SCons + Bazaar

    Look up a C/C++ Reference and learn How To Ask Questions The Smart Way
    Kindly rate my posts if you found them useful

  3. #3
    Join Date
    Nov 2009
    Posts
    18

    Question Re: static function to call member function on all objects?

    Quote Originally Posted by laserlight View Post
    You declared the vector, but never defined it. Define it in a source file.
    I'm not sure what syntax I would use for this. (I made a couple attempts already.)

    Also, for this simple dummy example, I would think I could just define it below the declaration. Correct?

    You probably need to have the destructor remove the object from the vector.
    I plan to, after I get the first part working. I didn't think that would be required just to demonstrate the point. Please correct me if I'm wrong.

    Thanks.

  4. #4
    Join Date
    Jan 2006
    Location
    Singapore
    Posts
    6,765

    Re: static function to call member function on all objects?

    Quote Originally Posted by cpengr
    I'm not sure what syntax I would use for this. (I made a couple attempts already.)
    For example:
    Code:
    vector<MyClass*> MyClass::vec;
    C + C++ Compiler: MinGW port of GCC
    Build + Version Control System: SCons + Bazaar

    Look up a C/C++ Reference and learn How To Ask Questions The Smart Way
    Kindly rate my posts if you found them useful

  5. #5
    Join Date
    Nov 2009
    Posts
    18

    Thumbs up Re: static function to call member function on all objects?

    Quote Originally Posted by laserlight View Post
    For example:
    Code:
    vector<MyClass*> MyClass::vec;
    That worked, thanks!

    (Somehow that syntax seems backwards to me, I didn't think of it..)

  6. #6

    Re: static function to call member function on all objects?

    Why don't you have a static class member instead and just change that? Have the objects themselves check it before they do anything to see if an update is needed.

  7. #7
    Join Date
    Jun 2009
    Location
    France
    Posts
    2,513

    Re: static function to call member function on all objects?

    Quote Originally Posted by cpengr View Post
    Hello all,

    I'm working in Borland C++ Builder v6.0 (maintenance/rewriting some code). I have a class where I'd like to have a static function call a member function on all instantiated members of the class. (Motive: update all at once, where the update function only exists as a member of the base class.)

    The way I thought to do this was to have a vector of pointers to the class inside the class itself. Upon construction, each object would add its "this" pointer to the vector. Then on calling the static function, iterate through all pointers in the vector, calling the update function.
    May I recommend using a Set instead (while you are going for a container solution)?

    Using a vector will give you big performance hit every time you destroy an object. You may think this doesn't happen too often, but keep in mind that when a vector re-allocates, for example, all of its content is re-built and re-constructed.

  8. #8
    Join Date
    Nov 2009
    Posts
    18

    Re: static function to call member function on all objects?

    Quote Originally Posted by originalfamousjohnsmith View Post
    Why don't you have a static class member instead and just change that? Have the objects themselves check it before they do anything to see if an update is needed.
    I couldn't figure a way to implement this. An "update individual" member function needs to be called once on every object when the static "update all" function is called. If I e.g. have a bool saying that "update all" has been called, set it true...how would I know when every individual object has been updated so I can set it false?

  9. #9
    Join Date
    Nov 2009
    Posts
    18

    Lightbulb Re: static function to call member function on all objects?

    Quote Originally Posted by monarch_dodra View Post
    May I recommend using a Set instead (while you are going for a container solution)?

    Using a vector will give you big performance hit every time you destroy an object. You may think this doesn't happen too often, but keep in mind that when a vector re-allocates, for example, all of its content is re-built and re-constructed.
    Cool, thanks, I will probably use that.

  10. #10
    Join Date
    Nov 2009
    Posts
    18

    Thumbs up Re: static function to call member function on all objects?

    The set seems to work nicely. Easier to erase items, too.

    Code:
    #include <vcl.h>
    #include <set>
    #include <iostream>
    #pragma hdrstop
    
    using std::cout;
    using std::set;
    
    //---------------------------------------------------------------------------
    
    class MyClass {
        public:
            MyClass();
            ~MyClass();
        private:
            static int count;
            static set<MyClass*> setOfPtrs;
            int num;
    };
    
    set<MyClass*> MyClass::setOfPtrs;
    int MyClass::count = 0;
    
    MyClass::MyClass() {
        num = count;
        cout << "creating " << num << '\n';
        count++;
        setOfPtrs.insert(this);
    }
    
    MyClass::~MyClass() {
        cout << "destroying " << num << '\n';
        count--;
        if (setOfPtrs.find(this) != setOfPtrs.end()) {
            cout << "\t(destructor found ptr.)\n";
        }
        setOfPtrs.erase(setOfPtrs.find(this));
    }
    
    //---------------------------------------------------------------------------
    
    void doit() {
        MyClass m1, m2, m3;
    }
    
    //---------------------------------------------------------------------------
    
    #pragma argsused
    int main(int argc, char* argv[])
    {
        doit();
        return 0;
    }

  11. #11
    Join Date
    Nov 2009
    Posts
    18

    Thumbs down Re: static function to call member function on all objects?

    Upon further inspection, this code, does not behave as I expected. The code is shown below, followed by its output.

    Questions:

    1.) In doit(), object #4 is destroyed right after it is created. I would expect that #2 should be destroyed, as #4 was assigned to #2's...reference? What is going on here?

    2.) Also in doit(), notice that #4 and #5 are reportedly destroyed twice; and #1 and #2 are never shown as being destroyed. How/why?

    3.) Regarding doitVecNoRef(), I guess these objects are going out of scope (from the for-loop)? Is there no way to populate a container of objects like this (conditionally or in a for-loop) and have the container handle the memory management? (I thought that's what they were for..?) Must I instead use a container of pointers to the objects with new/delete?


    Code:
    //---------------------------------------------------------------------------
    
    #include <vcl.h>
    #include <set>
    #include <vector>
    #include <iostream>
    #pragma hdrstop
    
    using std::cout;
    using std::set;
    using std::vector;
    
    //---------------------------------------------------------------------------
    
    class MyClass {
        public:
            MyClass();
            ~MyClass();
        private:
            static int count;
            static set<MyClass*> setOfPtrs;
            int num;
    };
    
    set<MyClass*> MyClass::setOfPtrs;
    int MyClass::count = 0;
    
    MyClass::MyClass() {
        num = ++count;
        setOfPtrs.insert(this);
        cout << "creating "   << num   << "; "
             << setOfPtrs.size() << " objects exist.\n";
    }
    
    MyClass::~MyClass() {
        if (setOfPtrs.find(this) == setOfPtrs.end()) {
            cout << "\t(destructor " << num
                 << " could not find ptr!!)\n";
        } else {
            cout << "destroying " << num   << "; ";
            setOfPtrs.erase(setOfPtrs.find(this));
            cout << setOfPtrs.size() << " objects exist.\n";
        }
    }
    
    //---------------------------------------------------------------------------
    
    void doit() {
        MyClass m1, m2, m3;
        m2 = MyClass();
        MyClass m4;
        m1 = m4;
    }
    
    //---------------------------------------------------------------------------
    
    void doitVecNoRef() {
        vector<MyClass> myVec;
        for (int i=0; i<3; i++) {
            myVec.push_back(MyClass());
        }
    }
    
    //---------------------------------------------------------------------------
    
    #pragma argsused
    int main(int argc, char* argv[])
    {
        doit();
        cout << '\n';
        doitVecNoRef();
        cout << '\n';
        return 0;
    }
    
    //---------------------------------------------------------------------------

    Output is as follows:


    creating 1; 1 objects exist.
    creating 2; 2 objects exist.
    creating 3; 3 objects exist.
    creating 4; 4 objects exist.
    destroying 4; 3 objects exist.
    creating 5; 4 objects exist.
    destroying 5; 3 objects exist.
    destroying 3; 2 objects exist.
    destroying 4; 1 objects exist.
    destroying 5; 0 objects exist.

    creating 6; 1 objects exist.
    destroying 6; 0 objects exist.
    creating 7; 1 objects exist.
    (destructor 6 could not find ptr!!)
    destroying 7; 0 objects exist.
    creating 8; 1 objects exist.
    (destructor 6 could not find ptr!!)
    (destructor 7 could not find ptr!!)
    destroying 8; 0 objects exist.
    (destructor 6 could not find ptr!!)
    (destructor 7 could not find ptr!!)
    (destructor 8 could not find ptr!!)


  12. #12
    Join Date
    Apr 1999
    Posts
    27,449

    Re: static function to call member function on all objects?

    Quote Originally Posted by cpengr View Post
    Upon further inspection, this code, does not behave as I expected.
    That is because you didn't consider that the compiler optimized your code.

    After you assigned to m2, you don't use it again, so the compiler is free to remove the object immediately. If you did something with m2 after you assigned it a MyClass(), then the compiler would not have destroyed the object. Not only that, the compiler is free to optimize away copy construction altogether. Change the compiler options, and you more than likely will see different output. So it really makes no sense trying to beat a dead horse -- change settings, you have a different outcome, change compilers (or even compiler versions), you may get another outcome.

    The bottom line is this -- do not write code assuming you can predict when any object will be destroyed (unless you dynamically created the object yourself, or the objects are not temporary). The thing you are seeing with your output is the way your compiler creates and destroys objects that are not dynamically created, and as far as I can tell, the compiler is not breaking any rules.

    Regards,

    Paul McKenzie
    Last edited by Paul McKenzie; November 20th, 2009 at 03:21 PM.

  13. #13
    Join Date
    Nov 2009
    Posts
    18

    Question Re: static function to call member function on all objects?

    Quote Originally Posted by Paul McKenzie View Post
    That is because you didn't consider that the compiler optimized your code.
    Thanks for your reply. I think there is more going on here than that, though. My compiler settings seem to show no optimizations:

    Project -> Options -> Compiler -> Code optimization = None

    Also, I added a Print() function to use the objects, and the results are mostly the same. See below.

    The bottom line is this -- do not write code assuming you can predict when any object will be destroyed (unless you dynamically created the object yourself, or the objects are not temporary). The thing you are seeing with your output is the way your compiler creates and destroys objects that are not dynamically created, and as far as I can tell, the compiler is not breaking any rules.
    Here, I would expect each object's this pointer to be added to the setOfPtrs at construction, and to be removed from setOfPtrs at destruction. However, it seems that one's destructor is removing another's this pointer...or these objects are being destroyed before their final usage...or they're intermingling somehow...?

    What am I doing wrong?

    Thanks.


    Code:
    //---------------------------------------------------------------------------
    
    #include <vcl.h>
    #include <set>
    #include <vector>
    #include <iostream>
    #pragma hdrstop
    
    using std::cout;
    using std::set;
    using std::vector;
    
    //---------------------------------------------------------------------------
    
    class MyClass {
        public:
            MyClass();
            ~MyClass();
            void Print();
        private:
            static int count;
            static set<MyClass*> setOfPtrs;
            int num;
    };
    
    set<MyClass*> MyClass::setOfPtrs;
    int MyClass::count = 0;
    
    MyClass::MyClass() {
        num = ++count;
        setOfPtrs.insert(this);
        cout << "creating "   << num   << "; "
             << setOfPtrs.size() << " objects exist.\n";
    }
    
    MyClass::~MyClass() {
        if (setOfPtrs.find(this) == setOfPtrs.end()) {
            cout << "\t(destructor " << num
                 << " could not find ptr!!)\n";
        } else {
            cout << "destroying " << num   << "; ";
            setOfPtrs.erase(setOfPtrs.find(this));
            cout << setOfPtrs.size() << " objects exist.\n";
        }
    }
    
    void MyClass::Print() {
        cout << "  #" << num << " exists\n";
    }
    
    //---------------------------------------------------------------------------
    
    void doit() {
        cout << "doit:\n";
        MyClass m1, m2, m3;
        m1.Print();
        m2.Print();
        m3.Print();
        m2 = MyClass();
        m2.Print();
        MyClass m4;
        m4.Print();
        m1 = m4;
        m1.Print();
    }
    
    //---------------------------------------------------------------------------
    
    void doitVecNoRef() {
        cout << "doitVecNoRef:\n";
        vector<MyClass> myVec;
        for (int i=0; i<3; i++) {
            myVec.push_back(MyClass());
        }
    
        for (vector<MyClass>::iterator it=myVec.begin(); it != myVec.end(); it++) {
            it->Print();
        }
    }
    
    //---------------------------------------------------------------------------
    
    #pragma argsused
    int main(int argc, char* argv[])
    {
        doit();
        cout << "\n\n";
        doitVecNoRef();
        cout << "\n\n";
        return 0;
    }
    //---------------------------------------------------------------------------
    Output:
    Code:
    doit:
    creating 1; 1 objects exist.
    creating 2; 2 objects exist.
    creating 3; 3 objects exist.
      #1 exists
      #2 exists
      #3 exists
    creating 4; 4 objects exist.
    destroying 4; 3 objects exist.
      #4 exists
    creating 5; 4 objects exist.
      #5 exists
      #5 exists
    destroying 5; 3 objects exist.
    destroying 3; 2 objects exist.
    destroying 4; 1 objects exist.
    destroying 5; 0 objects exist.
    
    
    doitVecNoRef:
    creating 6; 1 objects exist.
    destroying 6; 0 objects exist.
    creating 7; 1 objects exist.
            (destructor 6 could not find ptr!!)
    destroying 7; 0 objects exist.
    creating 8; 1 objects exist.
            (destructor 6 could not find ptr!!)
            (destructor 7 could not find ptr!!)
    destroying 8; 0 objects exist.
      #6 exists
      #7 exists
      #8 exists
            (destructor 6 could not find ptr!!)
            (destructor 7 could not find ptr!!)
            (destructor 8 could not find ptr!!)

  14. #14
    Join Date
    Nov 2008
    Location
    England
    Posts
    748

    Re: static function to call member function on all objects?

    Remember objects in stl containers are copied in and copied out. You store the this of a temporary yet this gets copied into the vector. MyClass relies on a default copy constructor, so your set becomes out-of-sync with the real this pointers.

    Provide a copy constructor that updates the set correctly.
    Get Microsoft Visual C++ Express here or CodeBlocks here.
    Get STLFilt here to radically improve error messages when using the STL.
    Get these two can't live without C++ libraries, BOOST here and Loki here.
    Check your code with the Comeau Compiler and FlexeLint for standards compliance and some subtle errors.
    Always use [code] code tags [/code] to make code legible and preserve indentation.
    Do not ask for help writing destructive software such as viruses, gamehacks, keyloggers and the suchlike.

  15. #15
    Join Date
    Apr 1999
    Posts
    27,449

    Re: static function to call member function on all objects?

    Quote Originally Posted by cpengr View Post
    Thanks for your reply. I think there is more going on here than that, though. My compiler settings seem to show no optimizations:
    Well, you're making my point.

    What if when optimizations are turned on (which you want turned on for release versions of your code), the output is different? What do you do then?

    Hopefully you are observing this behaviour only for educational purposes. If you are truly planning on writing a program based on when objects destroy themselves, then you're going about this the wrong way.

    Regards,

    Paul McKenzie

Page 1 of 2 12 LastLast

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured