const static initialization in Visual Studio

T

t

Lippman's C++ Primer says that if you initialize a const static data
member in a class, you still need to define the member outside the
class but without an initializer.

I tried it using Visual C++ 2005 Express edition and get this error:

1>Account.obj : error LNK2005: "private: static int const
Account::period" (?period@Account@@0HB) already defined in Account
Main.obj

Is this one of those things that vary by compiler? Is what Lippman
said from Standard C++?

My code is basically like this (lots of stuff omitted):


// Account.h
#ifndef ACCOUNT_H
#define ACCOUNT_H

class Account
{
static const int period = 30;
};

#endif

// Account.cpp

#include "Account.h"

const int Account::period;

// Account Main.cpp

#include "Account.h"

int main()
{
Account acc;
}
 
V

Victor Bazarov

t said:
Lippman's C++ Primer says that if you initialize a const static data
member in a class, you still need to define the member outside the
class but without an initializer.

I tried it using Visual C++ 2005 Express edition and get this error:

1>Account.obj : error LNK2005: "private: static int const
Account::period" (?period@Account@@0HB) already defined in Account
Main.obj

Is this one of those things that vary by compiler? Is what Lippman
said from Standard C++?

Yes. But it's only required for the variables that are used as
l-values (like when taking their address or binding a reference to
them). Try dropping the out-of-class definition since you're not
using it anyway.
My code is basically like this (lots of stuff omitted):


// Account.h
#ifndef ACCOUNT_H
#define ACCOUNT_H

class Account
{
static const int period = 30;
};

#endif

// Account.cpp

#include "Account.h"

const int Account::period;

// Account Main.cpp

#include "Account.h"

int main()
{
Account acc;
}

Can just be a bug in VC++. Ask in 'microsoft.public.vc.language'

V
 
B

Barry

Victor said:
Yes. But it's only required for the variables that are used as
l-values (like when taking their address or binding a reference to

Are you sure? where in standard mention this.
Comeau online happily accept this:
struct A
{
static const int value = 10;
};

//const int A::value; // not required by Comeau

int main()
{
int const* pi = &A::value;
}

I thought it was just like

const int SOME_CONST = 10;
int const* pi = &SOME_CONST;

the compiler automatically allocates memory for this const variable,
since we take its address.
 
B

Barry

t said:
Lippman's C++ Primer says that if you initialize a const static data
member in a class, you still need to define the member outside the
class but without an initializer.

I tried it using Visual C++ 2005 Express edition and get this error:

1>Account.obj : error LNK2005: "private: static int const
Account::period" (?period@Account@@0HB) already defined in Account
Main.obj

This is a compiler bug,
As I use VC++2005, it produces a compile error
"redefinition; multiple initialization"
 
V

Victor Bazarov

Barry said:
Are you sure? where in standard mention this.

Do you have a copy of the Standard? Then use it. If not, get one.
Comeau online happily accept this:
struct A
{
static const int value = 10;
};

//const int A::value; // not required by Comeau

int main()
{
int const* pi = &A::value;
}

Comeau online does not *link*, so if the definition is missing,
you would never know.
I thought it was just like

const int SOME_CONST = 10;
int const* pi = &SOME_CONST;

the compiler automatically allocates memory for this const variable,
since we take its address.

Yes, but here you have _defined_ the 'SOME_CONST', not just declared
it in a class definition.

V
 
J

James Kanze

Yes. But it's only required for the variables that are used as
l-values (like when taking their address or binding a reference to
them).

According to my copy of the C++ 1998 version of the standard,
it's required, period. The latest draft makes an exception for
variables which qualify for use in an integral constant
expression, and for which all uses result in an immediate lvalue
to rvalue conversion, but that's something which has been added.

Of course, failing to provide the definition is undefined
behavior, so it might work anyway. But since it's never wrong
to provide it, why not?
Try dropping the out-of-class definition since you're not
using it anyway.
Can just be a bug in VC++. Ask in 'microsoft.public.vc.language'

This is very definitly a serious bug in the compiler. If he
doesn't define the variable, VC++ compiles the code, *but* gives
Account::period different addresses in different compilation
units. (And of course, if you do take the address, most other
compilers will require the definition.)

In sum, you still cannot use this form of initializer in
portable code, but are stuck with the earlier use of enum, e.g.:

class Account
{
enum { period = 30 } ;
} ;

The type won't be right, but at least it will work portably.
 
J

James Kanze

Well, I tried, but couldn't locate the content.
:)

§3.2, paragraphes 2 and 3. The 1998 version of the standard
says:

An expression is potentially evaluated unless either it is
the operand of the sizeof operator, or it is the operand of
the typeid operator and does not designate an lvalue of
polymorphic class types. An object [Account::period is an
object] or non-overloaded function is *used* if its name
appears in a potentially-evaluated expression. [Lot's of
other things are used whenever...]

Every program shall contain exactly one definition of every
non-inline function or object that is used in that program;
no diagnostic required.

There isn't even the exception that Victor mentionned; if you
*use* Account::period, you must define it in exactly one
translation unit. (The declaration in the class definition is
just that, a declaration. See §3.1/2: "A declaration is a
definition unless [...], it declares a static data member in a
class declaration.)

The current draft is similar, but has added text in §3.2 to the
effect that if the object qualifies for use in an integral
constant expression, and all of its uses involve an immediate
lvalue to rvalue conversion, then no definition is necessary.
(Basically, the exception to the rule that Victor mentionned.)

(And yes, it is sometimes difficult to find the correct location
in the standard.)
 
G

Greg Comeau

According to my copy of the C++ 1998 version of the standard,
it's required, period. The latest draft makes an exception for
variables which qualify for use in an integral constant
expression, and for which all uses result in an immediate lvalue
to rvalue conversion, but that's something which has been added.

This is one of those "funny ones". At least as I recall it,
the committee voted for (at least) the sentiment of the words in the
latest draft to have originally been included in C++98, however the
words got lost in some shuffle. So it was basically a typo
defect in the standard, although, clearly, the words themselves
are absent in the C++98 text, implying that it's fair to argue that
the behavior was not in C++98 if one take it literally, which one
usually should.
 
J

James Kanze

This is one of those "funny ones". At least as I recall it,
the committee voted for (at least) the sentiment of the words in the
latest draft to have originally been included in C++98, however the
words got lost in some shuffle. So it was basically a typo
defect in the standard, although, clearly, the words themselves
are absent in the C++98 text, implying that it's fair to argue that
the behavior was not in C++98 if one take it literally, which one
usually should.

Well, it's not really a problem, since 1) failing to define the
variable is undefined behavior, and it actually works with all
existing compilers, if the conditions in the latest draft apply,
and 2) such constants tend to end up being used in lvalue
contexts anyway (e.g. by being passed to a template function
which takes a T const&), so it's just good practice to
systematically define then, regardless. (Personally, because of
2, I'm quite happy with the words in the current standard. They
have the advantage of being simpler, and easier to understand,
and the added freedom is not one I'll ever use.)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,999
Messages
2,570,243
Members
46,838
Latest member
KandiceChi

Latest Threads

Top