static variable in non-static member function

102 просмотра
Перейти к первому непрочитанному сообщению

Dave Steffen

не прочитано,
13 июл. 2007 г., 15:29:2713.07.2007

Hi Folks,

I'm about to use a mildly odd construct, and would like to know if
it's going to do what I think it's going to do. The issue is
static variables that are local to a non-static member function, and
the question is if they do what one would expect. Specifically, I'd
think that such variables are only constructed once, and are
essentially shared by all objects of that class; or, in other words,
act very much like class static member variables. Sample code:

#include <iostream>
using std::cout;
using std::endl;

class Talkative
{
public:
Talkative() { cout << "Ctor" << endl; }
Talkative(const Talkative&) { cout << "Copy Ctor " << endl;}
~Talkative() { cout << "Dtor" << endl;
}
};

class Foo {
public:
const Talkative& bar()
{
static Talkative talk;
return talk;
}
};

int main()
{
Foo foo;
Foo bar;
Foo baz;

foo.bar();
bar.bar();
baz.bar();

Talkative a = foo.bar();
const Talkative& c = baz.bar();
}

I think this program should output:

Ctor
Copy Ctor
Dtor
Dtor

GCC 4.0.4 agrees with me. Is this standard behavior? Can I count on
this on other machines?

Thanks!


--
Dave Steffen, Ph.D. "I say we invite opportunity inside
Software Engineer IV for a nice cup of tea, then hit her
Numerica Corporation on the head and steal her purse."
dgsteffen at numerica dot us -- Shlock Mercenary

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Thomas Tutone

не прочитано,
13 июл. 2007 г., 23:03:4713.07.2007
On Jul 13, 3:29 pm, Dave Steffen <dgstef...@numerica.us> wrote:

> I'm about to use a mildly odd construct, and would like to know if
> it's going to do what I think it's going to do. The issue is
> static variables that are local to a non-static member function,
> and
> the question is if they do what one would expect. Specifically,
> I'd
> think that such variables are only constructed once, and are
> essentially shared by all objects of that class; or, in other
> words,
> act very much like class static member variables.

Correct. Or to put it another way, they are like any other static
variable that appears in a function (whether member function or free-
standing).

Perhaps you are under the misimpression that each class object has its
own copy of the member function code, when typically all objects share
the same code (although not the same non-static member variables).
Even if a function is inlined, the standard requires that only a
single copy of the static variable be constructed.

Also - beware of the static initialization order fiaso
(http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.12) and the
potential problems using static variables in a multi-threaded
environment.

Best regards,

Tom

--

Bob Hairgrove

не прочитано,
13 июл. 2007 г., 23:05:2013.07.2007
{ Edits: double-spacing removed. -mod }

On Fri, 13 Jul 2007 13:29:27 CST, Dave Steffen
<dgst...@numerica.us> wrote:

>
>Hi Folks,
>
>I'm about to use a mildly odd construct, and would like to know if
>it's going to do what I think it's going to do. The issue is
>static variables that are local to a non-static member function, and
>the question is if they do what one would expect. Specifically, I'd
>think that such variables are only constructed once, and are
>essentially shared by all objects of that class; or, in other words,
>act very much like class static member variables.

Correct.

>#include <iostream>
>using std::cout;
>using std::endl;

Technically speaking, one should also #include <ostream> in order to
use std::endl -- however, most compilers seem to allow merely
including <iostream>...

[snip]

>I think this program should output:
>
>Ctor
>Copy Ctor
>Dtor
>Dtor
>
>GCC 4.0.4 agrees with me. Is this standard behavior? Can I count on
>this on other machines?

It is standard behavior. If the compiler implementations on the
"other machines" are also standard compliant, it should work OK.

--
Bob Hairgrove
NoSpam...@Home.com


--

Craig Scott

не прочитано,
14 июл. 2007 г., 16:31:0514.07.2007
On Jul 14, 5:29 am, Dave Steffen <dgstef...@numerica.us> wrote:
> I'm about to use a mildly odd construct, and would like to know if
> it's going to do what I think it's going to do. The issue is
> static variables that are local to a non-static member function, and
> the question is if they do what one would expect. Specifically, I'd
> think that such variables are only constructed once, and are
> essentially shared by all objects of that class; or, in other words,
> act very much like class static member variables.

Yes, your understanding is essentially correct. In the details below,
your static variable "talk" in Foo::bar() is a local static object.

You haven't asked about it directly, but the point of construction of
static objects generally may not be as simple as one might think. The C
++ standard has quite a bit to say about this, but it is kinda
distributed around the standard document somewhat and can be a bit
tedious to follow. There are sections of the C++ FAQ which talk around
this topic (10.12-16), but they don't sufficiently address it for my
liking. Since it seems to crop up on this list from time to time, I
include here my own abridged summary of some common cases, with a
conscious knowledge that there are bits I'm glossing over. First, two
bits of terminology used by the standard:

(1) Static objects essentially fall into two categories, local and non-
local. A local static object is generally a variable local to a
function (global or a member function) and declared static. A variable
at file/namespace scope or a static member variable of a class is non-
local. The storage for both local and non-local static objects shall
last for the duration of the program (3.7.1/1). The standard often
uses the term "static storage duration" which is what most people
think of when they think of a static object.

(2) Static initialization means an object is either zero-initialized
(see 8.5/5) or initialized with a constant expression. Everything else
is called dynamic initialization (3.6.2/1).


Armed with these two bits of terminology, some specific parts of the
standard can be noted. Firstly, consider 3.6.2/3, which says the
following for non-local objects with static storage duration:

"It is implementation-defined whether or not the dynamic
initialization (8.5, 9.4, 12.1, 12.6.1) of an object of namespace
scope is done before the first statement of main. If the
initialization is deferred to some point in time after the first
statement of main, it shall occur before the first use of any function
or object defined in the same translation unit as the object to be
initialized."

It is a common misconception that all namespace/file scope objects
(which have static storage duration) get initialized before main is
called. The standard doesn't actually require this, although it allows
it and maybe compilers generally do it this way. The standard only
requires that they be initialized before the first use of that object
in a function defined *in that translation unit*. Note that this is
weaker than the first use within a function in *any* translation unit
of the program. A consequence of this is that you really should avoid
referring to such an object other than through functions implemented
in the same translation unit as the object. At the very least, if you
are going to operate on a reference or pointer to such an object, you
should always obtain that reference or pointer through a function
defined in that object's translation unit. Relying on an extern
reference is not guaranteed to be safe. I suspect lots of people will
howl in protest at this statement, but it should be pointed out that
the rest of 3.6.2/3 gives an example of exactly this situation and
shows how an uninitialized object can be accessed as a result of using
extern instead of an accessor function of some sort.

For local objects with static storage duration, the standard is a bit
more explicit. Point 6.7/4 says this:

"The zero-initialization (8.5) of all local objects with static
storage duration (3.7.1) is performed before any other initialization
takes place. A local object of POD type (3.9) with static storage
duration initialized with
constant-expressions is initialized before its block is first entered.
An implementation is permitted to perform early initialization of
other local objects with static storage duration under the same
conditions that an
implementation is permitted to statically initialize an object with
static storage duration in namespace scope (3.6.2). Otherwise such an
object is initialized the first time control passes through its
declaration..."

In other words, the object is guaranteed to get initialized sometime
before the first call to the function in which it resides (which is
most people's expectation), and it is allowed to be created earlier in
some circumstances (not sure if this is understood so well by people).

As a final comment, the point of initialization really starts to
matter if your application deals with multiple threads. The current C+
+ standard is totally silent about threading, so for static objects
you more or less have to force some point where the object will be
initialized in a controlled manner (eg a startup thread before
multiple threads get a chance to access the object simultaneously).
Users of the Singleton design pattern will probably be nodding their
heads right about now. ;)

--
Computational Modeling, CSIRO (CMIS)
Melbourne, Australia


--

Dave Steffen

не прочитано,
17 июл. 2007 г., 11:08:5017.07.2007
Craig Scott <audiof...@gmail.com> writes:

> On Jul 14, 5:29 am, Dave Steffen <dgstef...@numerica.us> wrote:
> > I'm about to use a mildly odd construct, and would like to know if
> > it's going to do what I think it's going to do. The issue is
> > static variables that are local to a non-static member function,
> > and the question is if they do what one would expect.
> > Specifically, I'd think that such variables are only constructed
> > once, and are essentially shared by all objects of that class; or,
> > in other words, act very much like class static member variables.
>
> Yes, your understanding is essentially correct. In the details
> below, your static variable "talk" in Foo::bar() is a local static
> object.
>
> You haven't asked about it directly, but the point of construction of
> static objects generally may not be as simple as one might think. The C
> ++ standard has quite a bit to say about this, but it is kinda
> distributed around the standard document somewhat and can be a bit
> tedious to follow.

[...]

Yes, we've been thorough many of those issues, and debugging them is
all kinds of fun. :-) My question, really, was if a static variable
in a non-static member function was static in the way I expected it
to be; I had never used one before, and wanted to make sure I wasn't
about to fall off a cliff.

Thanks.

--
Dave Steffen, Ph.D. "I say we invite opportunity inside
Software Engineer IV for a nice cup of tea, then hit her
Numerica Corporation on the head and steal her purse."
dgsteffen at numerica dot us -- Shlock Mercenary

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Dave Steffen

не прочитано,
17 июл. 2007 г., 11:08:4517.07.2007
Thomas Tutone <Thomas...@yahoo.com> writes:

> On Jul 13, 3:29 pm, Dave Steffen <dgstef...@numerica.us> wrote:
>
> > I'm about to use a mildly odd construct, and would like to know if
> > it's going to do what I think it's going to do. The issue is
> > static variables that are local to a non-static member function,
> > and the question is if they do what one would expect.
> > Specifically, I'd think that such variables are only constructed
> > once, and are essentially shared by all objects of that class; or,
> > in other words, act very much like class static member variables.
>
> Correct. Or to put it another way, they are like any other static
> variable that appears in a function (whether member function or
> free- standing).
>
> Perhaps you are under the misimpression that each class object has its
> own copy of the member function code, when typically all objects share
> the same code (although not the same non-static member variables).
> Even if a function is inlined, the standard requires that only a
> single copy of the static variable be constructed.

No, I'm not under *that* misimpression. That's exactly what I
understood to be the case. I just wasn't sure that it *had* to be
that way. :-)

Thanks for the answer.

--
Dave Steffen, Ph.D. "I say we invite opportunity inside
Software Engineer IV for a nice cup of tea, then hit her
Numerica Corporation on the head and steal her purse."

ph (970) 461-2000 x227
dgsteffen at numerica d us -- Shlock Mercenary

Ответить всем
Написать сообщение автору
Переслать
0 новых сообщений