Hello I'm reading through Scott Meyer's book Effective C++, third Edition.

I'm having an issue understanding Page 14, Item 2, paragraph 4.

The below is a snippet of code with an explanation quoted from his book--

// Author: Scott Meyers

class GamePlayer{
     private:
         static const int NumTurns = 5; // constant declaration
         int score[NumTurns]; // use of constant
         ...
};


"What you see above is a declaration for NumTurns, not a definition. Usually, C++ requires that you provide a definition for anything you use, but class-specific constants that are static and of integral type (e.g., integers, chars and bools) are an exception. As long as you don't take their address, you can declare them and use them without providing a definition. If you do take the address of a class constant, or if your compiler incorrectly insists on a definition even if you don't take the address, you provide a separate definition like this;

"

const int GamePlayer::NumTurns; // definition of NumTurns...

Maybe I'm not understanding the part bolded. I made this program to try to confirm my understanding of not being able to take an address of the class declared member, and I was capable of doing so without any issue.

Here's the code I use to test the example provided--

// Effective_CPP_Practice_1.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>

class GamePlayer{
	public:
		static const int NumTurns = 5;

		GamePlayer(){
		}
};

//const int GamePlayer::NumTurns;

int main()
{
	const int& iRef = GamePlayer::NumTurns; // taking the address of GamePlayer::NumTurns...?
	std::cout << iRef << std::endl; // no run-time error either??


	return 0;
}

--compiled this through the Visual C++ program. What am I doing wrong?

I guess.. just because you can do something doesn't mean you should.. What version of VC++ do you use? If I remember correctly, it didn't use to be possible to create even a static integer in-class declaration in VC++.. because I've had to use enums to achieve the same effect previously..

I can imagine that the reason it's allowable to define a constant integer at the same place as the declaration ( something which would usually result in multiple definitions every time the header was included ) is that a constant integer can just be 'copied' everywhere its used ( much the same as an inline function ), so taking the address of the variable would be impossible without a single definition, since there'd be no single address.

Compiling with g++, I get a reasonable error, well, compiling is fine, but linking fails.

[matt@localhost ~]$ g++ -Wall testabc.cpp
/tmp/cccdhGzW.o: In function `main':
testabc.cpp:(.text+0x190): undefined reference to `GamePlayer::NumTurns'
collect2: ld returned 1 exit status
[matt@localhost ~]$

By "taking the address" I believe it means using the address-of operator (&). An example of taking the address of something:

int x;
int* y = &x; // here we take the address of x and assign it to the pointer y

The "definition" part it talks about should be implemented something like below. Assume you have GamePlayer class defined in GamePlayer.h and the actual implementation is in GamePlayer.cpp:

// GamePlayer.h
class GamePlayer{
   public:
      static const int NumTurns = 5;

      GamePlayer();
};
// GamePlayer.cpp
#include "GamePlayer.h"

const int GamePlayer::NumTurns; // definition of NumTurns... 

GamePlayer::GamePlayer() {
   // constructor code here
}

I'm using VC++ Express Edition

The book states that the technique isn't portable across older compilers (due to the fact that initialization wasn't allowed for field data types in classes for those versions).

Edit: I'll have to reread through the current section to make any further comments--

By "taking the address" I believe it means using the address-of operator (&). An example of taking the address of something:

int x;
int* y = &x; // here we take the address of x and assign it to the pointer y

See my comment below--

The "definition" part it talks about should be implemented something like below. Assume you have GamePlayer class defined in GamePlayer.h and the actual implementation is in GamePlayer.cpp:

// GamePlayer.h
class GamePlayer{
   public:
      static const int NumTurns = 5;

      GamePlayer();
};
// GamePlayer.cpp
#include "GamePlayer.h"

const int GamePlayer::NumTurns; // definition of NumTurns... 

GamePlayer::GamePlayer() {
   // constructor code here
}

This isn't exactly what I'm misunderstanding. The author made this clear to me already. It's what he means by taking the address of the value when it is declared and not defined.


I've tried using the ampersand symbol to reference the address of the value and assigning it to a pointer. The result is the same as the code I posted.

// Effective_CPP_Practice_1.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>

class GamePlayer{
	public:
		static const int NumTurns = 5;

		GamePlayer(){
		}
};

//const int GamePlayer::NumTurns;

int main()
{
	const int *iPtr = &GamePlayer::NumTurns; // taking the address of GamePlayer::NumTurns...?
	std::cout << *iPtr << std::endl; // no run-time error either??
	return 0;
}

Again, just because you can do something on one compiler doesn't mean that you should. See the output I posted when trying to compile your code with G++ 4.2.1. ( a very recent version ).

If I uncomment the line const int GamePlayer::NumTurns; , then the linker error goes away ( still with G++ ).

Maybe VC++ has been lax about issuing an error, and/or has implemented the feature in a way that differs from other compilers. For best portability, follow this author's recommendation.

Again, just because you can do something on one compiler doesn't mean that you should. See the output I posted when trying to compile your code with G++ 4.2.1. ( a very recent version ).

If I uncomment the line const int GamePlayer::NumTurns; , then the linker error goes away ( still with G++ ).

Maybe VC++ has been lax about issuing an error, and/or has implemented the feature in a way that differs from other compilers. For best portability, follow this author's recommendation.

It's not that I ignored your post. I replied to the other individual with what I understood.

This is probably the best answer, and is a good lesson to have multiple compilers on hand instead of just one.

Curse the competitive compiler vendors! @_@

-Alex

see IS 9.4.2/4

"...The member shall still be defined in a namespace scope if it is used in the program and the namespace scope definition shall not contain an initializer".

GCC is conforming. static constant member object is 'used' (in main) and, therefore, has to be defined.

the main issue here is that if you take the address, the static object has to retain the same address across all translation units. (required for object identity). AFAIK, VC++ 2005 seems to satisfy this requirement.

stroustrup's FAQ on this: http://www.research.att.com/~bs/bs_faq2.html#in-class

This article has been dead for over six months. Start a new discussion instead.