3

head.h


#pragma once

namespace foo
{
    int bar;

    int funct1();
}

head.cpp

#include "head.h"

int foo::funct1()
{
    return bar;
}

main.cpp

#include <iostream>

#include "head.h"


int main()
{
    foo::bar = 1;
    std::cout << foo::funct1() << std::endl;
    return 0;
}

Error LNK2005 "int foo::bar" (?bar@foo@@3HA) already defined in head.obj

I don't understand what is going on. I tried looking for the answer but everyone's questions are so specific to their code and don't even look close to the problem that I am having.

I am not including .cpp files into main. I am not redefining anything. I am literally just assigning 1 to the variable then returning it with a function in the same namespace. How is it being defined multiple times?

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
JwGaming
  • 79
  • 6
  • 2
    Possible duplicate of [Variable definition in header files](https://stackoverflow.com/questions/2216765/variable-definition-in-header-files) – Mike van Dyke Jun 24 '19 at 11:09
  • 1
    *How is it being defined multiple times?* -- You must have not realized what `#pragma once` is supposed to do. It doesn't mean "this is only declared once in my entire program". – PaulMcKenzie Jun 24 '19 at 11:11
  • Possible duplicate of [Variable definition in header files](https://stackoverflow.com/questions/2216765/variable-definition-in-header-files) – L. F. Jun 25 '19 at 04:56

6 Answers6

7

The header head.h is included in two compilation units head.cpp and main.cpp. So the variable bar is defined twice. You could declare the variable without its definition the following way

#pragma once

namespace foo
{
    extern int bar;

    int funct1();
}

and then define it in some cpp module.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • Thank you. I never actually used this before on a variable. I couldn't understand how it was a problem since it is not a problem with classes or structs. – JwGaming Jun 24 '19 at 11:23
  • 1
    @JwGaming Types and objects are two different things. – Lightness Races in Orbit Jun 24 '19 at 11:25
  • @JwGaming *it is not a problem with classes or structs.* -- It certainly is a problem with classes and structs if you had done the same thing. `struct foo {}; foo f;` If you had that in a header, you would have gotten the same error. – PaulMcKenzie Jun 24 '19 at 13:08
4

This foo namespace-level bar declaration:

namespace foo
{
    int bar;
}

is actually a definition.

To make it a declaration, mark the bar as extern in head.h:

namespace foo
{
    extern int bar;
}

Then define it in head.cpp:

int foo::bar = 0;
Ron
  • 14,674
  • 4
  • 34
  • 47
2

head.h is included in both main.cpp and head.cpp. So the variable is defined twice.

Possible Solution: make it inline. The "extern" solutions are also good, although older in approach.

namespace foo
{
    inline int bar;
}
Aykhan Hagverdili
  • 28,141
  • 6
  • 41
  • 93
Michael Chourdakis
  • 10,345
  • 3
  • 42
  • 78
2

How is it being defined multiple times?

It is defined once in head.cpp and once in main.cpp. That is a total of two times. This violates the one definition rule, which states that there may only be one definition for every variable.

int bar;

This is a definition of a variable. You've included it into two translation units.

A variable can be declared without definition in an extern declaration:

extern int bar;

Replace the definition with such declaration, and put the definition into exactly one translation unit.

eerorika
  • 232,697
  • 12
  • 197
  • 326
2

I am not redefining anything. I am literally just assigning 1 to the variable

You're redefining the variable!

head.cpp has one via #include "head.h", and main.cpp has one via #include "head.h".

You need to merely declare it (unusual but not too strange) in the header:

extern int bar;

…then define it in one translation unit. This is just like what you do with static class members (albeit with slightly different syntax).

Since C++17, you may do this by instead plopping the inline keyword on to your definition.

Alternatively, avoid mutable globals…

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • I had no idea there was a difference. I assumed it /was/ a declaration and that it became defined the moment it was given a value and not before. Only that the compiler needed a way to link all the uses together as it would not be used before the first time it was given a value. – JwGaming Jun 24 '19 at 14:14
  • @JwGaming It's an old wives' tale that the first assignment to an object is a "definition" or "initialisation". It's not; it's an assignment to an object that was already defined and constructed (and potentially default-constructed) previously. Most variable declarations are also definitions; we can use `extern` to suppress the definition part. – Lightness Races in Orbit Jun 24 '19 at 15:27
1

Do carefully note that foo is not a class, but a namespace. When you declare a free variable in the header file:

int bar;

And then #include this header file multiple times (into different CPP files, causing multiple translation unit compilations), you'd get a linker error. Everyone knows it.

And, you'd add extern attribute at the declaration, and define the variable elsewhere in one of the CPP/C file.

Putting a global variable into a namespace is nothing but giving the global variable a different name. Think if foo::bar as foo__NS__bar, and hence you must add extern in the header and define foo::bar at some locatoin.

Note that this is different from a non-static member variable of a class. A class variable doesn't need to be defined/declared this way since the class is a type. Each instantiated variable of class-type would have a separate copy of the variable. Further to that, when you add a static variable in the class, you are giving that logically global variable another name. Thence, you must have that static-variable defined one of the CPP file.

Ajay
  • 18,086
  • 12
  • 59
  • 105