Static member and namespace - a puzzle.

R

rossum

Either I have found a puzzle, or I am just being stupid. Inside a
namespace I have a class with a static const double member. The
member is not an int so I cannot initialise it within the class, I
have to initialise it outside the class. The problem is that when I
tried putting the initialisation in the header file immediately after
the class my compiler (g++) rejected it, citing "multiple definition":

g++.exe alphaMain.o alpha.o -o "Alpha.exe" -L"C:/DEV-CPP/lib"
alpha.o(.text+0x0):alpha.cpp: multiple definition of
`foo::AlphaC::m_doubl'
alphaMain.o(.text+0x0):alphaMain.cpp: first defined here

Then I tried moving the initialisation outside the namespace, but
still in the header file. Same error. Finally I put the
initialisation at the end of the .cpp file, outside the namespace
again. That seemed to work and compiled with no errors.

Another aspect to the puzzle is that when I concatenate the three
files: alpha.h, alpha.cpp and alphaMain.cpp into a single file then it
compiles normally with the initialisation where I first put it, after
the class and inside the namespace.

I can't see that I am doing anything stupid, can another pair of eyes
see my error?


rossum
(Getting ready to say "Doh!" and bang my head on the keyboard.)



// alpha.h -----------------------

#ifndef ALPHA_H_INCLUDE
#define ALPHA_H_INCLUDE

namespace foo {

class AlphaC {
private:
static const double m_doubl;
int m_data;

public:
AlphaC() : m_data(0) {}

void increment();
}; // end class AlphaC

// const double AlphaC::m_doubl = 1.0; // This doesn't work,
// but it does work if the 3 files are combined into one.

} // end namespace foo

// const double foo::AlphaC::m_doubl = 1.0; // This doesn't work

#endif // ALPHA_H_INCLUDE

// alpha.cpp ---------------------

#include "alpha.h"

namespace foo {

void AlphaC::increment() {
++m_data;
} // end increment()

} // end namespace foo

const double foo::AlphaC::m_doubl = 1.0; // This works. Why?


// alphaMain.cpp -----------------

#include "alpha.h"

int main() {
foo::AlphaC my_alpha;

my_alpha.increment();

return 0;

} // end main()
 
J

Jonathan Mcdougall

Either I have found a puzzle, or I am just being stupid. Inside a
namespace I have a class with a static const double member. The
member is not an int so I cannot initialise it within the class, I
have to initialise it outside the class. The problem is that when I
tried putting the initialisation in the header file immediately after
the class my compiler (g++) rejected it, citing "multiple definition":

That's quite normal, because if you include the header twice, the member
gets defined twice, and that's illegal.
g++.exe alphaMain.o alpha.o -o "Alpha.exe" -L"C:/DEV-CPP/lib"
alpha.o(.text+0x0):alpha.cpp: multiple definition of
`foo::AlphaC::m_doubl'

alpha.cpp : that's one.
alphaMain.o(.text+0x0):alphaMain.cpp: first defined here

alphaMain.cpp : that' two.
Another aspect to the puzzle is that when I concatenate the three
files: alpha.h, alpha.cpp and alphaMain.cpp into a single file then it
compiles normally with the initialisation where I first put it, after
the class and inside the namespace.

Because you end up with only one file.

The ODR (One Definition Rule) states that you can only have one
definition for all names (with some exceptions). So

int main()
{
int a;
int a; // violates ODR
}

And

// in my_header.h
int a;

// in 1.cpp
# include <my_header.h> // first definition

// in 2.cpp
# include <my_header.h> // second, bang you're dead.


The usual way to work with statics initialization is to do it in the
impl file :

// c.h
class C
{
static int my_int;
};

// c.cpp
int C::my_int = 3;

So my_int is initialized in one place only.


Jonathan
 
V

Victor Bazarov

rossum said:
Either I have found a puzzle, or I am just being stupid. Inside a
namespace I have a class with a static const double member. The
member is not an int so I cannot initialise it within the class, I
have to initialise it outside the class. The problem is that when I
tried putting the initialisation in the header file immediately after
the class my compiler (g++) rejected it, citing "multiple definition":
[...]

Pull the definition out of the header. Imagine that instead of writing
'#include "alpha.h"' in your source files you simply stuff the contents
of that header into those source files (that's what the pre-processor
essentially does). How many modules contain your definition now? So,
why are you surprised?
Then I tried moving the initialisation outside the namespace, but
still in the header file. Same error. Finally I put the
initialisation at the end of the .cpp file, outside the namespace
again. That seemed to work and compiled with no errors.

Another aspect to the puzzle is that when I concatenate the three
files: alpha.h, alpha.cpp and alphaMain.cpp into a single file then it
compiles normally with the initialisation where I first put it, after
the class and inside the namespace.

Well, how many translation units are there when you concatenate the
three files? How many definitions of the static data member?
I can't see that I am doing anything stupid, can another pair of eyes
see my error?

Do you really need an extra pair of eyes for that? I think you need
a better book.

V
 
R

rossum

On Tue, 23 Nov 2004 23:34:12 GMT, "Victor Bazarov"

Thanks for the replies Jonathan and Victor,
rossum said:
Either I have found a puzzle, or I am just being stupid. Inside a
namespace I have a class with a static const double member. The
member is not an int so I cannot initialise it within the class, I
have to initialise it outside the class. The problem is that when I
tried putting the initialisation in the header file immediately after
the class my compiler (g++) rejected it, citing "multiple definition":
[...]

Pull the definition out of the header. Imagine that instead of writing
'#include "alpha.h"' in your source files you simply stuff the contents
of that header into those source files (that's what the pre-processor
essentially does). How many modules contain your definition now? So,
why are you surprised?
When I constructed the single file, I left both the #include<alpha.h>
lines in as well as the copy of the file, so that file included the
definition three times.

I put include guards in the header file to avoid the problem of
including things more than once, and they seem to have worked OK with
the single file.

I thought that the second time the header file was encountered it
would be ignored. Is it that the include guards only work across a
single compilation unit and do not work between different compilation
units? What is the lifetime of a given #define?

<bangs head on keyboard> hjm hgujc v

[snip]
Do you really need an extra pair of eyes for that? I think you need
a better book.

No, but I may need to read it more thoroughly: TC++PL (3rd edition).


rossum
 
J

Jonathan Mcdougall

rossum said:
On Tue, 23 Nov 2004 23:34:12 GMT, "Victor Bazarov"
rossum said:
Either I have found a puzzle, or I am just being stupid. Inside a
namespace I have a class with a static const double member. The
member is not an int so I cannot initialise it within the class, I
have to initialise it outside the class. The problem is that when I
tried putting the initialisation in the header file immediately after
the class my compiler (g++) rejected it, citing "multiple definition":
[...]

Pull the definition out of the header. Imagine that instead of writing
'#include "alpha.h"' in your source files you simply stuff the contents
of that header into those source files (that's what the pre-processor
essentially does). How many modules contain your definition now? So,
why are you surprised?

When I constructed the single file, I left both the #include<alpha.h>
lines in as well as the copy of the file, so that file included the
definition three times.

I put include guards in the header file to avoid the problem of
including things more than once, and they seem to have worked OK with
the single file.


Something like

# include "alpha.h" // first definition

// alpha.h stuff manually copied here
// second definition

// the rest of the file

Where's that third definition? And that should not have compiled if a
name is defined twice (once in the header and once in the copied lines).
I thought that the second time the header file was encountered it
would be ignored.

The language does not mandate that, that's why we use include guards.
Is it that the include guards only work across a
single compilation unit and do not work between different compilation
units?
Yes.

What is the lifetime of a given #define?

A translation unit.


Jonathan
 
R

rossum

On Tue, 23 Nov 2004 21:32:45 -0500, Jonathan Mcdougall

[snip]
A translation unit.

Yes, I worked that out while trying to get to sleep. I had got into
the habit of thinking of defines as "global" so I got stuck on the
idea that they survived across translation units. Thinking about it
(rather than assuming) made it clear that they do not.

Thanks for your help, the dialogue helped me to see things more
clearly.

Doh!

gbfc ,kij

Doh!

gjf,jmf gfjvbf

Doh!

f,jvj,fgjm j

rossum
 

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

No members online now.

Forum statistics

Threads
474,181
Messages
2,570,970
Members
47,536
Latest member
VeldaYoung

Latest Threads

Top