-
November 3rd, 2009, 02:42 PM
#1
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;
}
-
November 3rd, 2009, 02:45 PM
#2
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.
-
November 3rd, 2009, 02:54 PM
#3
Re: static function to call member function on all objects?
Originally Posted by laserlight
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.
-
November 3rd, 2009, 02:56 PM
#4
Re: static function to call member function on all objects?
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;
-
November 3rd, 2009, 03:45 PM
#5
Re: static function to call member function on all objects?
Originally Posted by laserlight
For example:
Code:
vector<MyClass*> MyClass::vec;
That worked, thanks!
(Somehow that syntax seems backwards to me, I didn't think of it..)
-
November 4th, 2009, 04:30 AM
#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.
-
November 4th, 2009, 05:08 AM
#7
Re: static function to call member function on all objects?
Originally Posted by cpengr
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.
-
November 4th, 2009, 01:58 PM
#8
Re: static function to call member function on all objects?
Originally Posted by originalfamousjohnsmith
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?
-
November 4th, 2009, 01:59 PM
#9
Re: static function to call member function on all objects?
Originally Posted by monarch_dodra
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.
-
November 4th, 2009, 02:32 PM
#10
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;
}
-
November 20th, 2009, 02:28 PM
#11
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!!)
-
November 20th, 2009, 03:10 PM
#12
Re: static function to call member function on all objects?
Originally Posted by cpengr
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.
-
November 20th, 2009, 03:51 PM
#13
Re: static function to call member function on all objects?
Originally Posted by Paul McKenzie
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!!)
-
November 20th, 2009, 05:31 PM
#14
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.
-
November 20th, 2009, 06:16 PM
#15
Re: static function to call member function on all objects?
Originally Posted by cpengr
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
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
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|