void Foo()
{
static int v = 0; // Only accessible in Foo
...
}
This feature, that has existed since the days of C, is really useful because
it essentially allows you to declare global variables but with the added
benefit of having the global be controlled by only a certain portion of the
code (the function). Of course, this control is enforced by the compiler.
In C++, when implementing a member function of a certain class, I often find
myself wanting to declare a member variable, but one that would be only
scoped to that member function. I cannot use static in this case because
this would only create ONE instance of the variable for ALL instances of my
class. It would be a great feature of the language if one could do something
like the following:
class Bar
{
public:
void DoSomething()
{
static_member int v = 0; // Only accesible in DoSomething(), one
instance per instance of Bar
...
}
};
Here, the fictional static_member keyword would essentially make 'v' a data
member of the class Bar, but that could only be accessed by the
DoSomething() member function. I know that such a feature would bring up
many important issues, such as:
* Should sizeof() on a class instance include the size of static_member
variables?
* How can you initialize static_members? Can it be done in a constructor? Or
should it be initialized on declaration, just like regular local statics?
Anyway, I was just wondering if anyone else has thought about this, and what
your feelings are on this.
Thanks!
--
Antonio Maiorano
Software Engineer, Electronic Arts
E-Mail: m a i o r a n o AT v i d e o t r o n DOT c a
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
> In C++, when implementing a member function of a certain class, I often find
> myself wanting to declare a member variable, but one that would be only
> scoped to that member function. I cannot use static in this case because
> this would only create ONE instance of the variable for ALL instances of my
> class. It would be a great feature of the language if one could do something
> like the following:
> class Bar
> {
> public:
> void DoSomething()
> {
> static_member int v = 0; // Only accesible in DoSomething(), one
> instance per instance of Bar
> ...
> }
> };
Well, C++ of course can't currently do that. You can emulate by making
"v" a private member of "bar" and "avoid touching", though that's "less nice"
than what you like to. Another nicer approach would be to make "DoSomething"
a member of an inner class of Bar. Since "DoSomething" could be considered
to be more than a function member - namely a function with some data - you
can as well consider this as an inner object of "Bar"; this way, it is also
hidden from non-members of your inner class:
class Bar {
class SomethingDoer {
int v = 0;
class Bar *outher;
public:
SomethingDoer(class Bar *bar)
: outher(bar)
{ }
void DoSomething() {}
} m_SomethingDoer;
};
Then it is of course a noisiance(sp?) to access members of "Bar" since
you always have to implicitly go thru the "outher" pointer.
> Here, the fictional static_member keyword would essentially make 'v' a data
> member of the class Bar, but that could only be accessed by the
> DoSomething() member function. I know that such a feature would bring up
> many important issues, such as:
> * Should sizeof() on a class instance include the size of static_member
> variables?
Of course, since the compiler has to include it in each instance. It would
rather hide it away from other members.
> * How can you initialize static_members? Can it be done in a constructor? Or
> should it be initialized on declaration, just like regular local statics?
Well, your proposed syntax makes sense, and it would be only consistent
if one could *not* touch this member in the constructor. However, this rises
another more serious question: *When* is the member initiated? Implicitly
as part of the constructor? What happens if the constructor of this member
throws? In which order are these members constructed? Do we need to fix one?
I'd guess that most of these implications can be answered and I would also
believe that it would be possible to support this style.
> Anyway, I was just wondering if anyone else has thought about this, and what
> your feelings are on this.
Personally, I haven't had the need for this, but I guess it might not be
impossible to support - the construction issues of these members can clearly
be well-defined. Compiler support for them would be a bit messy, though.
So long,
Thomas
Antonio Maiorano schrieb:
[snip]
>In C++, when implementing a member function of a certain class, I often find
>myself wanting to declare a member variable, but one that would be only
>scoped to that member function. I cannot use static in this case because
>this would only create ONE instance of the variable for ALL instances of my
>class. It would be a great feature of the language if one could do something
>like the following:
>
>class Bar
>{
>public:
> void DoSomething()
> {
> static_member int v = 0; // Only accesible in DoSomething(), one
>instance per instance of Bar
> ...
> }
>};
>
>Here, the fictional static_member keyword would essentially make 'v' a data
>member of the class Bar, but that could only be accessed by the
>DoSomething() member function. I know that such a feature would bring up
>many important issues, such as:
>* Should sizeof() on a class instance include the size of static_member
>variables?
>* How can you initialize static_members? Can it be done in a constructor? Or
>should it be initialized on declaration, just like regular local statics?
>
>Anyway, I was just wondering if anyone else has thought about this, and what
>your feelings are on this.
>
>
If I understand your proposal correctly, static_member declares just a
normal non-static data member,
right? So, before I go on and answer your questions it should be
clarified, in which way such localized
**static** data members should be managed? Of course something like
class Bar
{
public:
void DoSomething() // Could be even a static member function in this case!
{
static static_member int v = 0; // Only accesible in DoSomething()
...
}
};
could be a feasible solution and would add one further flavour in the
meaning of static ;-)).
"* Should sizeof() on a class instance include the size of static_member
variables?"
- I hope yes, otherwise your proposal would violate the basic object
concept of C++.
"* How can you initialize static_members? Can it be done in a
constructor? Or should it be initialized on
declaration, just like regular local statics?"
- Initialization would work like initialization of non-data member local
static's, it cannot be done in the
c'tor.
My personal opinion is, that I can't get a warm feeling with that
proposal, because it leads to more new
problems than it solves: While you localize the accessibility of such
data member, you create an artifical
separation among all data members. If you study c'tor effects you would
need to study **every**
member function to look for localized members, too.
I think, you should try to analyze the reasons for such special
localization of a data member. To my opinion,
the need for such thingy arises because of a badly-formed separation of
responsabilities in a given class
design. I.e. the wish for such a feature could be resolved much better
by redesigning those classes, and
obviously this special "local" member should part of another class.
Hope that helps,
Daniel Krügler
> Daniel Krügler schrieb:
> [snip]
> If I understand your proposal correctly, static_member declares just a
> normal non-static data member,
> right? So, before I go on and answer your questions it should be
> clarified, in which way such localized
> **static** data members should be managed? Of course something like
>
> class Bar
> {
> public:
> void DoSomething() // Could be even a static member function in this
case!
> {
> static static_member int v = 0; // Only accesible in
DoSomething()
> ...
> }
> };
>
> could be a feasible solution and would add one further flavour in the
> meaning of static ;-)).
- Heh heh, yeah, of course this wouldn't make much sense :)
> "* Should sizeof() on a class instance include the size of static_member
> variables?"
> - I hope yes, otherwise your proposal would violate the basic object
> concept of C++.
- That's what I thought as well.
> "* How can you initialize static_members? Can it be done in a
> constructor? Or should it be initialized on
> declaration, just like regular local statics?"
> - Initialization would work like initialization of non-data member local
> static's, it cannot be done in the
> c'tor.
>
> My personal opinion is, that I can't get a warm feeling with that
> proposal, because it leads to more new
> problems than it solves: While you localize the accessibility of such
> data member, you create an artifical
> separation among all data members. If you study c'tor effects you would
> need to study **every**
> member function to look for localized members, too.
- Yes, which is why I was considering whether they should be initialized in
the constructor.
> I think, you should try to analyze the reasons for such special
> localization of a data member. To my opinion,
> the need for such thingy arises because of a badly-formed separation of
> responsabilities in a given class
> design. I.e. the wish for such a feature could be resolved much better
> by redesigning those classes, and
> obviously this special "local" member should part of another class.
- Since I posted this question, I have looked more carefully at my code and
effectively moved the code into a separate subclass, making my
'static_member' a regular data member of this class. I realize now that I
was simply suffering from the good 'ol coherency problem in which too much
responsibility was being given to my single class. However, I will say that
my first instinct was not to have to code an entirely new class to solve my
problem because apart from it being more work, it would also pollute the
header file with something the client shouldn't see anyway. This got me to
thinking about static variables in functions, and the wishful thinking began
:)
> Hope that helps,
>
> Daniel Krügler
Thanks for the feedback!
Cheers!
--
Antonio Maiorano
Software Engineer, Electronic Arts
E-Mail: m a i o r a n o AT v i d e o t r o n DOT c a
>* How can you initialize static_members? Can it be done in a constructor? Or
>should it be initialized on declaration, just like regular local statics?
On declaration. Otherwise it's not localized in a function and it
loses much of its (limited) appeal.
Problem: This variable must obviously be destroyed in the containing
object's destructor. But since it will be created only when the flow
reached it. We therefor need to keep track of which static_members
were created and which weren't (example follows).
All in all I can see what need prompted the suggestion but I don't
think it has much merit.
class X {
public:
void foo() { static_member string s; }
void bar() { static_member string s; } // not foo::s!
};
int main()
{
X a, b;
a.foo();
b.bar();
}
// a needs to destroy foo.s but not bar.s
// b needs to destroy bar.s but not foo.s
void Bar::doSomething() {
static std::map<Bar*,int> map;
int &v = map[this];
This solution has the following problems.
1. It isn't thread safe.
2. When the instance is destroyed nothing does (or can) clean up
the map entry.
3. After the instance is destroyed a new instance can be created
at the same address. The new instance will then get the old
instance's int instead of a new defaultly constructed one.
4. It takes log(N) time to look up the variable where N is the
number of Bars created so far (at distinct addresses).
I might have missed a few details but I think the afore mentioned
problems are sufficient in making this solution unusable.
I'm pretty sure defaultly isn't really a word but you know what I
mean.
> Allan W wrote:
> > void Bar::doSomething() {
> > static std::map<Bar*,int> map;
> > int &v = map[this];
> > }
Motti Lanzkron <mlan...@yahoo.co.uk> wrote
> This solution has the following problems.
> 1. It isn't thread safe.
Also true of the OP's original static variable.
> 2. When the instance is destroyed nothing does (or can) clean up
> the map entry.
Destroyed on program termination, just like the OP's original static
variable.
> 3. After the instance is destroyed a new instance can be created
> at the same address. The new instance will then get the old
> instance's int instead of a [newly-]constructed one.
That's true. Whether this is a problem depends on the way it's used.
Note that initialization in the constructor(s) would normally handle
this issue.
3a. When the instance is destroyed, the integer in the map remains
until program termination, unless it's re-used by creating
another object at exactly the same address.
Probably a bigger problem for some apps -- depending on why it's used.
> 4. It takes log(N) time to look up the variable where N is the
> number of Bars created so far (at distinct addresses).
Why is that a problem? Think of it as a "virtual data member" -- there
is overhead, but log(N) isn't very bad unless N is huge.
> I might have missed a few details but I think the afore mentioned
> problems are sufficient in making this solution unusable.
In what context?
Note that I'm not suggesting that this technique be used on a widespread
basis. I'm just saying that it appears to (mostly) implement what the
OP was asking for... good or bad.