# Confused as to why this wont compile

This topic is 2125 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Hi Guys,

I am scratching my head at the moment with this one.

I have a class which I have stripped right back to bare bones trying to work out why it wont compile in my app.

 #pragma once class Asset { public: Asset() { ++(this->nID); // Asset ID (auto-increments) } ~Asset() { } private: static int nID; }; int Asset::nID=0; 

When I compile in my main application I get the following error;

"private: static int Asset::nID" ([email="?nID@Asset@@0HA"]?nID@Asset@@0HA[/email]) already defined in framework.obj

I have taken the above and put it into a brand new C++ project and it compiles fine.

I cant understand why it wont compile in the 'primary' application I am working with.

Even if I change the nID variable to something else, then the new variable name is 'already defined'. So, it isn't a variable redefinition problem.

Any ideas on this would by hugely appreciated.

##### Share on other sites
Posted · Hidden
Hidden
Hi Guys,

I am scratching my head at the moment with this one.

I have a class which I have stripped right back to bare bones trying to work out why it wont compile in my app.

 #pragma once class Asset { public: Asset() { ++(this->nID); // Asset ID (auto-increments) } ~Asset() { } private: static int nID; }; int Asset::nID=0; 

When I compile in my main application I get the following error;

"private: static int Asset::nID" ([email="?nID@Asset@@0HA"]?nID@Asset@@0HA[/email]) already defined in framework.obj

I have taken the above and put it into a brand new C++ project and it compiles fine.

I cant understand why it wont compile in the 'primary' application I am working with.

Even if I change the nID variable to something else, then the new variable name is 'already defined'. So, it isn't a variable redefinition problem.

Any ideas on this would by hugely appreciated.

try setting the value inside the class or something

##### Share on other sites
"int Asset::nID=0;" is defining the variable.
So put it into a .cpp file rather than header.

##### Share on other sites
Put the
int Asset::nID=0;

##### Share on other sites
Don't know if that's the whole header file you posted here but, in case it is, it's best practice to wrap the code in a header with "#ifndef" directives.

example: name_of_file.h
 #ifndef NAME_OF_FILE_HEADER #define NAME_OF_FILE_HEADER //Put your code here... #endif 

If you don't do this you may have conflict issues when compiling.

Good luck! Edited by TMarques

##### Share on other sites
Source code (a.cpp, x.h) --(preprocessor)--> compilation_unit ---(compiler)--> a.o/.obj Source code (b.cpp, x.h) --(preprocessor)--> compilation_unit ---(compiler)--> b.o/.obj --(linker)--> executable Source code (c.cpp, x.h) --(preprocessor)--> compilation_unit ---(compiler)--> c.o/.obj

cpp file #includes header (.h) files. Compiler then converts stuff in those into code and symbols. nAssets is a symbol. At that point it's just a reference to something unknown, compiler doesn't care about it beyond a name.

Since each cpp is processed independently, we end up with 3 object files, each containing their own copy of nAssets. When linker puts all 3 together, it has 3 copies of nAssets.

By putting nAssets into .cpp file, such as (a.cpp), it will only generate one symbol, avoiding the confusion.

Header guard (pragma once) only prevents inclusion into same compilation unit. If x.h is included multiple times when preprocessing a.cpp, it will only appear the first time. But it will be included fully again when preprocessing b.cpp and c.cpp.

int Asset::nID=0;[/quote]This line actually says: "reserve 4 bytes inside executable at precisely this location. When someone needs nAssets symbol, give them this pointer".

Unlike most other languages, it's more than just semantic annotation, it's fairly important choice on where to put it.

it's best practice to wrap the code in a header with "#ifndef" directives.[/quote]

It is, but pragma once is fairly well supported these days and does the same. I prefer header guards myself. Edited by Antheus

##### Share on other sites
Putting the variable into a CPP file did the job.

I still don't understand why a straight cut and paste of the same code into a new project worked ok, though. Must be one of those strange compiler things.

Thanks guys, I was starting to tear my hair out.

##### Share on other sites

I still don't understand why a straight cut and paste of the same code into a new project worked ok, though. Must be one of those strange compiler things.

Definition in header will work as long as the header is included in only one CPP.
That's to say, the definition is in only one translate unit.
If the header is included in more than one CPPs, it won't link due to duplicated definition. Edited by wqking

##### Share on other sites

I still don't understand why a straight cut and paste of the same code into a new project worked ok, though. Must be one of those strange compiler things.

Because your new project probably either a) only includes the header once or b) you copied the class into a cpp file.

##### Share on other sites
Hi guys,

The file was included only once (in both projects) and was header only (no cpp file). Isnt it the job of #pragma once to stop multiple inclusions anyway (using VC2008)?

Anyway, it is working great now. Thanks guys.

##### Share on other sites

The file was included only once (in both projects) and was header only (no cpp file). Isnt it the job of #pragma once to stop multiple inclusions anyway (using VC2008)?

Header only? At least your header will be include to any cpp file eventually to use, right?
Each cpp fill be expanded as a translate unit (with all headers are expanded to it).
If the definition is appearing in only one translate unit, that's fine. But if it's appearing in more than one translate unit, link error.

See One Definition Rule here
http://en.wikipedia.org/wiki/One_Definition_Rule

##### Share on other sites
Isnt it the job of #pragma once to stop multiple inclusions anyway (using VC2008)?

I strongly suggest to read Antheus post, because I really wish more people would actually care about how compiling and linking works.

#include doesn't mean "use this as a source to look up stuff". It means "recursively copy/paste the whole frigging thing and everything it includes". If in this whole mess of headers including headers including headers the same header appears twice, then and ONLY then pragma once or inclusion guards come into play.

Header files on their own are never compiled, so you can't have a project that is "header only". Nothing will really happen when compiling this.

Every .cpp file is compiled completely in isolation. It doesn't matter what might be in other files. Some compilers might make special exceptions for inline and template code, but you might notice that those are exactly the two things that should be entirely defined in header files, if you expect them to work.

After every .cpp file in your project has been compiled to an .obj file, the linker will try to piece them together and make the final binary (.dll, .exe). In THIS stage, you got your error about multiple definitions, long after anybody cares about headers or inclusions guards. All that matters is having the same definition in two different .obj files.

##### Share on other sites
As an additional note, this is not necessary when accessing nID. nID is not a non-static data member, therefore this has no effect on it. The difference between the three assignment lines:

struct Thing { Thing() { Thing::oooh = 11; oooh = 12; this->oooh = 13; } static int oooh; }; 

Is a matter of clarity. I would personally prefer the first syntax, as it explicitly calls it out as a static member. The second syntax would be acceptable as well. The latter syntax, while valid, is extremely unclear and can introduce confusion.

##### Share on other sites
making a global var in headers dont work, even if you put it in a namespace, it doesn't work. if you make it static, it'll compile but it's value is only accessible by the class that set it's value. You must set it in a cpp, I hate using globals but if i do use them i keep them in main.cpp for easy reference Edited by Muzzy A