Skip to contentSkip to conversation

"static const" attribute in C++ (How to ?)

DISCUSSION Luciano Moreira - igLnx 7 participants 20 messages Jun 28, 2004 – Jul 2, 2004 1 message not in the archive

lore
Share & tools
lore
#0 lore raw

Is very commom in Java, the declaration of "static const" attributes into class escope. Is possible to do anything similar in C++ ? Using another techniques ?

All we need is to have a public static symbol into a class escope that can be used to declare a array, intead of using a lot of global symbols.

Thanks,

Luciano

Quoted 33 lines · Glynn Clements
Quoted 6 lines · Luciano Moreira - igLnx

Sorry for this rookie question, but I'm not a experienced C++ programmer (I m a old C-ANSI programmer, not in C++)

How can us create a kind of "static const" attribute into a class ? I need to use it like as:
char myArray[MYCLASS::DEFSIZE];

That won't work. Array sizes have to be constant expressions (expressions which contain only literal values).

Quoted 12 lines

Where "DEFSIZE" whould be a "static const" member (or another type) of MYCLASS.

What do I already tried ? Follow:

class MYCLASS {
   public:
      static const int DEFSIZE;
};

const int DEFSIZE = 100;

But, when the file "MYCLASS.h" is included more than one file ".cpp", the linker says that the member "MYCLASS::DEFZISE" "was already defined in 'filename'". And don't have occurrences of compiler errors, only on linking.

Definitions belong in source (.cpp) files, not header files.

#1 lore raw
Quoted 6 lines · Luciano Moreira - igLnx

Is very commom in Java, the declaration of "static const" attributes into class escope. Is possible to do anything similar in C++ ? Using another techniques ?

All we need is to have a public static symbol into a class escope that can be used to declare a array, intead of using a lot of global symbols.

It appears that you are allowed to initialise constant static members within the declaration, so you can do this:

	class Foo
	{
	public:
		static const int DEFSIZE = 100;
	};
	
	class Bar
	{
	public:
		char myArray[Foo::DEFSIZE];
	};

This compiles with "g++ -ansi -pedantic", so it's probably standard ISO C++.

Signature · 1 line
Glynn Clements <[email protected]>
#2 lore raw

Of corse, it's was my first attempt. But, the compiler says that "pure specifier can only be specified for functions". Thus the below code seems to be incorrect.

	class Foo
	{
	public:
		static const int DEFSIZE = 100;
	};

Luciano

Glynn Clements wrote:

Quoted 31 lines · Glynn Clements
Quoted 6 lines · Luciano Moreira - igLnx

Is very commom in Java, the declaration of "static const" attributes into class escope. Is possible to do anything similar in C++ ? Using another techniques ?

All we need is to have a public static symbol into a class escope that can be used to declare a array, intead of using a lot of global symbols.

It appears that you are allowed to initialise constant static members within the declaration, so you can do this:

	class Foo
	{
	public:
		static const int DEFSIZE = 100;
	};
	
	class Bar
	{
	public:
		char myArray[Foo::DEFSIZE];
	};

This compiles with "g++ -ansi -pedantic", so it's probably standard ISO C++.

#3 lore raw

Just put the definition in the cpp file.

Header File:
class Foo

{
	public:
		static const int DEFSIZE;
};

in CPP-File:

const int Foo::DEFSIZE=100

Why does this not work for you?

Henry

Signature · 2 lines
Hi! I'm a .signature virus! Copy me into your
~/.signature to help me spread!
#4 lore raw

Because, the compiler doesn't know the value of the symbol DEFSIZE when it is used for a array declaration, like as:
char myArray[MYCLASS::DEFSIZE];

Then, we have the conclusion that the value atribution should be in header file (.h) - for that case. But, I tried the use of "enum", and now it's working well.

Luciano

Quoted 21 lines · Henry Margies

Just put the definition in the cpp file.

Header File:
class Foo

{
	public:
		static const int DEFSIZE;
};

in CPP-File:

const int Foo::DEFSIZE=100

Why does this not work for you?

Henry

#5 lore raw

Hello Luciano,

Quoted 7 lines · On Tue, 29 Jun 2004 16:10:15 -0300 Luciano Moreira - igLnx…

Because, the compiler doesn't know the value of the symbol DEFSIZE when it is used for a array declaration, like as:
char myArray[MYCLASS::DEFSIZE];

Then, we have the conclusion that the value atribution should be in header file (.h) - for that case. But, I tried the use of "enum", and now it's working well.

Of course #define'd values can be used in array range. Such value is not dynamically interpreted, since the pre processor is performing substitution of macros before the compiler gets the file.

Did you try to maintain you const int in the header file and to encapsulate it like this:

[beginning of .h file]
#ifndef MY_CLASS_H
#define MY_CLASS_H

// .. here the previous content of your .h file

#endif
[EOF]

My 2 cts..

Regards,

Quoted 28 lines
Quoted 11 lines · Henry Margies

Just put the definition in the cpp file.

Header File:
class Foo

{
	public:
		static const int DEFSIZE;
};

in CPP-File:

Quoted 10 lines

const int Foo::DEFSIZE=100

Why does this not work for you?

Henry

-
To unsubscribe from this list: send the line "unsubscribe linux-c-programming" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

Signature · 1 line
wwp

A message that is not in the archive (sent off-list or not yet received): [email protected]

#7 lore raw

Yeah, of course. All my headers has "once" inclusion control.

Luciano

Quoted 76 lines · wwp

Hello Luciano,

Quoted 6 lines · On Tue, 29 Jun 2004 16:10:15 -0300 Luciano Moreira - igLnx…

Because, the compiler doesn't know the value of the symbol DEFSIZE when it is used for a array declaration, like as:
char myArray[MYCLASS::DEFSIZE];

Then, we have the conclusion that the value atribution should be in header file (.h) - for that case. But, I tried the use of "enum", and now it's working well.

Of course #define'd values can be used in array range. Such value is not dynamically interpreted, since the pre processor is performing substitution of macros before the compiler gets the file.

Did you try to maintain you const int in the header file and to encapsulate it like this:

[beginning of .h file]
#ifndef MY_CLASS_H
#define MY_CLASS_H

// .. here the previous content of your .h file

#endif
[EOF]

My 2 cts..

Regards,

Quoted 34 lines
Quoted 11 lines · Henry Margies

Just put the definition in the cpp file.

Header File:
class Foo

{
	public:
		static const int DEFSIZE;
};

in CPP-File:

Quoted 12 lines

const int Foo::DEFSIZE=100

Why does this not work for you?

Henry

-
To unsubscribe from this list: send the line "unsubscribe linux-c-programming" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#8 lore raw
In reply to Luciano Moreira - igLnx
Quoted 3 lines · Luciano Moreira - igLnx

Of corse, it's was my first attempt. But, the compiler says that "pure specifier can only be specified for functions". Thus the below code seems to be incorrect.

It works for me with both egcs-2.91.66 and gcc-3.0.3.

Signature · 1 line
Glynn Clements <[email protected]>
#9 lore raw
In reply to Glynn Clements
Quoted 25 lines · Glynn Clements
Quoted 6 lines · Luciano Moreira - igLnx

Is very commom in Java, the declaration of "static const" attributes into class escope. Is possible to do anything similar in C++ ? Using another techniques ?

All we need is to have a public static symbol into a class escope that can be used to declare a array, intead of using a lot of global symbols.

It appears that you are allowed to initialise constant static members within the declaration, so you can do this:

	class Foo
	{
	public:
		static const int DEFSIZE = 100;
	};
	
	class Bar
	{
	public:
		char myArray[Foo::DEFSIZE];
	};
Quoted 2 lines

This compiles with "g++ -ansi -pedantic", so it's probably standard ISO C++.

Does this also work when put in a header or only when put directly in the cpp file?

Quoted 12 lines
Signature · 10 lines
-- 
Glynn Clements <[email protected]>
-
To unsubscribe from this list: send the line "unsubscribe linux-c-programming" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
 
 +++++++++++++++++++++++++++++++++++++++++++
 This Mail Was Scanned By Mail-seCure System
 at the Tel-Aviv University CC.
#10 lore raw
Quoted 8 lines · Micha Feigin
Quoted 5 lines

It appears that you are allowed to initialise constant static members within the declaration, so you can do this:

This compiles with "g++ -ansi -pedantic", so it's probably standard ISO C++.

Does this also work when put in a header or only when put directly in the cpp file?

It doesn't matter. A #include directive simply inserts the contents of the header file directly into the source code which is fed to the compiler. The compiler doesn't care which file a given piece of code comes from.

Signature · 1 line
Glynn Clements <[email protected]>
#11 lore raw
Quoted 9 lines · Glynn Clements
Quoted 6 lines · Micha Feigin
Quoted 5 lines

It appears that you are allowed to initialise constant static members within the declaration, so you can do this:

This compiles with "g++ -ansi -pedantic", so it's probably standard ISO C++.

Quoted 8 lines
Quoted 2 lines

Does this also work when put in a header or only when put directly in the cpp file?

It doesn't matter. A #include directive simply inserts the contents of the header file directly into the source code which is fed to the compiler. The compiler doesn't care which file a given piece of code comes from.

It is a problem since a header can be included more then once, and since the static value is put into the data section of the object, the linker should give an error if the file was included more the once since it will have multiple definitions for the same variable and it wont know how to link the objects (it doesn't care if it the same values, it does care if the static variable gets its value more then once).

I had that problem with the arpack++ library which is implemented in headers only and it sets such a variable and crashes miserably if I split the code between files.

Quoted 11 lines
Signature · 9 lines
Glynn Clements <[email protected]>
-
To unsubscribe from this list: send the line "unsubscribe linux-c-programming" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
 
 +++++++++++++++++++++++++++++++++++++++++++
 This Mail Was Scanned By Mail-seCure System
 at the Tel-Aviv University CC.
#12 lore raw
Quoted 14 lines · Micha Feigin
Quoted 6 lines
Quoted 6 lines
Quoted 5 lines

It appears that you are allowed to initialise constant static members within the declaration, so you can do this:

This compiles with "g++ -ansi -pedantic", so it's probably standard ISO C++.

Quoted 7 lines
Quoted 2 lines

Does this also work when put in a header or only when put directly in the cpp file?

It doesn't matter. A #include directive simply inserts the contents of the header file directly into the source code which is fed to the compiler. The compiler doesn't care which file a given piece of code comes from.

Quoted 7 lines

It is a problem since a header can be included more then once, and since the static value is put into the data section of the object, the linker should give an error if the file was included more the once since it will have multiple definitions for the same variable and it wont know how to link the objects (it doesn't care if it the same values, it does care if the static variable gets its value more then once).

But in this case, there isn't a variable. Foo::DEFSIZE is a compile-time constant; it doesn't exist in memory. Compiling the code in question and running "nm" on both the object files and the resulting executable confirms this.

If it was treated as a constant lvalue (i.e. stored in the .rodata section), you wouldn't be able to use it to specify the array dimension.

I can't state for certain that this is defined behaviour, because I don't have a copy of the ISO C++ standard. OTOH, it works with "g++ -ansi -pedantic ...", and that's usually fairly rigorous about generating errors for non-standard code.

Signature · 1 line
Glynn Clements <[email protected]>
#13 lore raw
Quoted 9 lines · Glynn Clements
Quoted 2 lines · Micha Feigin
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

It appears that you are allowed to initialise constant static members within the declaration

[...]

But in this case, there isn't a variable. Foo::DEFSIZE is a compile-time constant; it doesn't exist in memory.

So what happens if you try to take its address?

--
Daniel Brockman
[email protected]

#14 lore raw
Quoted 9 lines · Daniel Brockman
Quoted 7 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

It appears that you are allowed to initialise constant static members within the declaration

[...]

But in this case, there isn't a variable. Foo::DEFSIZE is a compile-time constant; it doesn't exist in memory.

So what happens if you try to take its address?

You get a link error, unless you also add a definition in one of the source files.

Signature · 1 line
Glynn Clements <[email protected]>
#15 lore raw
In reply to Micha Feigin

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Micha Feigin wrote:

| On Tue, Jun 29, 2004 at 06:43:23PM +0100, Glynn Clements wrote:
|
|>It doesn't matter. A #include directive simply inserts the contents of
|>the header file directly into the source code which is fed to the
|>compiler. The compiler doesn't care which file a given piece of code
|>comes from.
|>
|
| It is a problem since a header can be included more then once, and

Umm.

#import "foo.h"

This includes only one time. I'd only use this with Objective-C though.

For C, and in general, you should use:

#ifndef __FOO_H__
#define __FOO_H__

....

#endif /*__FOO_H__*/
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.4 (GNU/Linux)
Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org

iD8DBQFA4yUShDd4aOud5P8RAkoxAJ9mYFKq+MYzPsX+LGbg/iTDA+UFqQCfYnMv 2Tn7bkzzlPu66jmrOamHJW8=
=nfHE
-----END PGP SIGNATURE-----

#16 lore raw
Quoted 14 lines · John Richard Moser
|>It doesn't matter. A #include directive simply inserts the contents of
|>the header file directly into the source code which is fed to the
|>compiler. The compiler doesn't care which file a given piece of code
|>comes from.
|>
|
| It is a problem since a header can be included more then once, and

Umm.

#import "foo.h"

This includes only one time. I'd only use this with Objective-C though.

Quoted 8 lines

For C, and in general, you should use:

#ifndef __FOO_H__
#define __FOO_H__

....

#endif /*__FOO_H__*/

That only prevents against the header being included multiple times within a given compilation unit, which isn't the issue which was being discussed. The issue was that, if an lvalue is defined (as opposed to declared) in a header file, it will exist in every object file whose source code included the header.

The key point is that C++ appears to treat initialised "static const" members as compile-time constants, not as lvalues. Thus, they don't exist in any object file, and so the problem of them existing in multiple object files doesn't arise.

Signature · 1 line
Glynn Clements <[email protected]>
#17 lore raw
Quoted 32 lines · Glynn Clements
Quoted 14 lines · John Richard Moser
|>It doesn't matter. A #include directive simply inserts the contents of
|>the header file directly into the source code which is fed to the
|>compiler. The compiler doesn't care which file a given piece of code
|>comes from.
|>
|
| It is a problem since a header can be included more then once, and

Umm.

#import "foo.h"

This includes only one time. I'd only use this with Objective-C though.

Quoted 8 lines

For C, and in general, you should use:

#ifndef __FOO_H__
#define __FOO_H__

....

#endif /*__FOO_H__*/

That only prevents against the header being included multiple times within a given compilation unit, which isn't the issue which was being discussed. The issue was that, if an lvalue is defined (as opposed to declared) in a header file, it will exist in every object file whose source code included the header.

Quoted 4 lines

The key point is that C++ appears to treat initialised "static const" members as compile-time constants, not as lvalues. Thus, they don't exist in any object file, and so the problem of them existing in multiple object files doesn't arise.

That can't be true; What happens if the static int value is defined in another file? it's value won't be known at compile time, only at link time. What g++ may be doing is ignoring the problem of multiple definitions if they have the same value.

It does allow initializing array size using static const, unlike gcc, I don't know the mechanism, but I believe it also requires linker support, not only compiler.

I compiled a sample program with a static const int val = 10; and then ran nm on it and in the output:

a.out:080484c4 r val

so the value is in the object, read only data if I recall the section symbols correctly.

Quoted 12 lines
Signature · 10 lines
-- 
Glynn Clements <[email protected]>
-
To unsubscribe from this list: send the line "unsubscribe linux-c-programming" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
 
 +++++++++++++++++++++++++++++++++++++++++++
 This Mail Was Scanned By Mail-seCure System
 at the Tel-Aviv University CC.
#18 lore raw
Quoted 8 lines · Micha Feigin
Quoted 4 lines

The key point is that C++ appears to treat initialised "static const" members as compile-time constants, not as lvalues. Thus, they don't exist in any object file, and so the problem of them existing in multiple object files doesn't arise.

That can't be true; What happens if the static int value is defined in another file? it's value won't be known at compile time, only at link time.

By "initialised", I'm referring to the situation where they are initialised in the class declaration. See my previous example.

Quoted 2 lines

What g++ may be doing is ignoring the problem of multiple definitions if they have the same value.

No.

The class declaration doesn't cause any lvalues to be created. There are no definitions in the object file. Try it.

Quoted 3 lines

It does allow initializing array size using static const, unlike gcc, I don't know the mechanism, but I believe it also requires linker support, not only compiler.

No.

In most situations, the size of an array has to be known at compile time. If the array is a local variable, its size will affect the the frame offsets of any local variables which are below it in the stack frame. If the array is a structure field, its size will affect the size of the structure. If you multiply by sizeof(array), the compiler will often generate different code depending upon whether sizeof(array) is a power of two. And so on.

The only exceptions are in declarations where you don't need to specify the size, e.g.:

	extern int array[];
and:
	void foo(int array[]);

Anywhere that you have to specify a size, the size needs to be known at compile time (variable-sized automatic arrays are permitted in C99, but not in C89 or C++, although gcc will allow them unless you use -pedantic; variable-sized global arrays and structure fields aren't allowed anywhere and aren't supported by gcc).

Quoted 7 lines

I compiled a sample program with a static const int val = 10; and then ran nm on it and in the output:

a.out:080484c4 r val

so the value is in the object, read only data if I recall the section symbols correctly.

That's a variable definition, not a class declaration.

Here's a concrete example:

	$ cat foo.cc
	#include <stdio.h>
	class Foo
	{
	public:
		static const int DEFSIZE = 100;
	};
	
	int main(void) {
		printf("%d\n", Foo::DEFSIZE);
		return 0;
	}

	$ g++ -c -ansi -pedantic -Wall foo.cc
	$ nm foo.o
	00000000 T main
	         U printf
	$ g++ foo.o
	$ ./a.out 
	100

If you try to use Foo::DEFSIZE as an lvalue (e.g. taking its address), you will get a link error unless you actually add a definition for it. But you can use it as a value without supplying a definition, and nothing will appear in the object file. Also, if it's initialised in the declaration, you can omit the initialiser from any subsequent definition, i.e.:

	$ cat foo.cc
	#include <stdio.h>
	class Foo
	{
	public:
		static const int DEFSIZE = 100;
	};
	
	const int Foo::DEFSIZE;
	const int *ptr = &Foo::DEFSIZE;
	
	int main(void) {
		printf("%d\n", *ptr);
		return 0;
	}

	$ g++ -ansi -pedantic -Wall foo.cc
	$ ./a.out
	100
Signature · 1 line
Glynn Clements <[email protected]>
#19 lore raw
In reply to Glynn Clements

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Glynn Clements wrote:

| John Richard Moser wrote:
|
|
|>|>It doesn't matter. A #include directive simply inserts the contents of
|>|>the header file directly into the source code which is fed to the
|>|>compiler. The compiler doesn't care which file a given piece of code
|>|>comes from.
|>|>
|>|
|>| It is a problem since a header can be included more then once, and
|>
|>Umm.
|>
|>#import "foo.h"
|>
|>This includes only one time.  I'd only use this with Objective-C though.
|>
|>For C, and in general, you should use:
|>
|>#ifndef __FOO_H__
|>#define __FOO_H__
|>
|>....
|>
|>#endif /*__FOO_H__*/
|
|
| That only prevents against the header being included multiple times
| within a given compilation unit, which isn't the issue which was being
| discussed. The issue was that, if an lvalue is defined (as opposed to
| declared) in a header file, it will exist in every object file whose
| source code included the header.
|

yeah, externally linked rather than staticly linked. If you declare them static, they won't be associated with an object symbol, thus it's like they don't exist in relation to linking multiple objects together.

It goes like this:

int foo; /*We can say 'extern int foo' somewhere and access this from another compilation unit*/
static int bar; /*This we can't.*/

| The key point is that C++ appears to treat initialised "static const"
| members as compile-time constants, not as lvalues. Thus, they don't
| exist in any object file, and so the problem of them existing in
| multiple object files doesn't arise.

Actually, they're the same as regular consts; they just don't get an exported symbol, so they're invisible to the other compilation units. They STILL get a position in the data segment!

|
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.4 (GNU/Linux)
Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org

iD8DBQFA47lshDd4aOud5P8RAumVAJ9CmfPM1lUlOvDQjT3Dz8CG9ayg4QCZAekl e5/IVRksVVq0HldmWYFDcv8=
=6vVS
-----END PGP SIGNATURE-----

#20 lore raw
In reply to Micha Feigin

Your previous suggestion is fine !!!
I tried to use "enum" and it's working well. Thus, it's a way to encapsulate a constant into a class escope.

Of course that, it isn't the better way to encapsulate constants into a class escope like the use of "static const" (like as in Java), but it's working.

If someone have anothers tecniques, they ll be welcome.

Thank you all,
Luciano

Quoted 59 lines · Micha Feigin
Quoted 25 lines · Glynn Clements
Quoted 6 lines · Luciano Moreira - igLnx

Is very commom in Java, the declaration of "static const" attributes into class escope. Is possible to do anything similar in C++ ? Using another techniques ?

All we need is to have a public static symbol into a class escope that can be used to declare a array, intead of using a lot of global symbols.

It appears that you are allowed to initialise constant static members within the declaration, so you can do this:

	class Foo
	{
	public:
		static const int DEFSIZE = 100;
	};
	
	class Bar
	{
	public:
		char myArray[Foo::DEFSIZE];
	};
Quoted 4 lines

This compiles with "g++ -ansi -pedantic", so it's probably standard ISO C++.

Does this also work when put in a header or only when put directly in the cpp file?

Quoted 13 lines
Signature · 9 lines
Glynn Clements <[email protected]>
-
To unsubscribe from this list: send the line "unsubscribe linux-c-programming" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

+++++++++++++++++++++++++++++++++++++++++++
This Mail Was Scanned By Mail-seCure System
at the Tel-Aviv University CC.

-
To unsubscribe from this list: send the line "unsubscribe linux-c-programming" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html