1

I was playing around with namespaces when I encountered a lnk2005 error. I can't figure out how to get around the error. Here's the error:

1>Source.obj : error LNK2005: "int Chart::Bars::d" (?d@Bars@Chart@@3HA) already defined in Chart.obj
1>Source.obj : error LNK2005: "class foo Chart::l" (?l@Chart@@3Vfoo@@A) already defined in Chart.obj
1>Source.obj : error LNK2005: "int Chart::t" (?t@Chart@@3HA) already defined in Chart.obj
1>C:\Users\bnm\dev\examples\play\nmspca\Debug\nmspca.exe : fatal error LNK1169: one or more multiply defined symbols found
1>
1>Build FAILED.
1>
1>Time Elapsed 00:00:00.49
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

Here's the code...

Chart.h

#pragma once

#include "foo.h"

namespace Chart
{
    int t;

    foo l;

    namespace Bars
    {

        int d;
    }

}

Foo.h

#pragma once

class foo
{
public:
    int ss;
    char* h;

};

Chart.cpp

#include "Chart.h"

using namespace Chart;

int main ()
{
    l.h = "g";
}

Source.cpp

#include "Chart.h"

using namespace Chart;

int test()
{
    l.ss = 0;

    return l.ss;
}

When the #include "Chart.h" from Source.cpp is removed the problems goes away. However, Source.cpp needs #include "Chart.h" for the namespace definition.

What's the correct way to express that "namespace Chart" is needed in both Chart.cpp and Source.cpp so that everything compiles?

Nicholas Smith
  • 11,642
  • 6
  • 37
  • 55
brimaa
  • 169
  • 3
  • 11
  • #pragma once doesn't protect you against having the same symbols defined in multiple TUs. – PlasmaHH Feb 26 '13 at 13:59
  • Aren't they the same as include guards? http://en.wikipedia.org/wiki/Pragma_once – brimaa Feb 26 '13 at 14:47
  • They are, and also include guards don't protect you against having the same symbols defined in multiple TUs. They only work for the current TU. How can they know that you are going to later link some other TU that may contain the same symbol too? – PlasmaHH Feb 26 '13 at 14:51
  • My understanding was that the include guards and pragma commands blocked the entire H file from being included more than once in the compile. So if Source.cpp and Chart.cpp both included Chart.h, Chart.h would just be brought in once (thus symbols defined once and no link confusion) for any .cpp or other file that referenced it. If a header is brought in for the entire app just once then the symbols in it should only be defined once and the compiler should (it seems) be able to find symbols without confusion. Is this not correct? Is there more to it? – brimaa Feb 27 '13 at 01:21
  • include guards and pragma once can only work for the current file being compiled. If you compile multiple files, and generate multiple object files, all of them will contain one of the symbols defined in the header included by all .cpp files. when you link all the objects together, there are multiple definitions. pragma once can not do anything about this, since it does not know there are other objects that you intend to later compile together. Even if it could detect that, not including the header file would lead to compile errors, since the object defined is not visible in that TU. – PlasmaHH Feb 27 '13 at 10:04

3 Answers3

6

If you define any objects in a header file and include that header file in multiple translation units, those objects are now defined multiple times. This is the problem you're having. The declarations of t, l, and d introduce objects and you have done so in a header file.

The proper method for supporting namespace scope variables is to declare them as extern in the header file. This makes them declarations only and not definitions. Then, in a single implementation file, define them.

Change Chart.h to:

#pragma once

#include "foo.h"

namespace Chart
{
    extern int t;

    extern foo l;

    namespace Bars
    {

        extern int d;
    }

}

Then in an implementation file, perhaps Chart.cpp, do:

int Chart::t;
foo Chart::t;
int Chart::Bars::d;
Joseph Mansfield
  • 108,238
  • 20
  • 242
  • 324
  • 3
    While this is the technically correct solution to the problem at hand, there is another guideline I would recommend, that will prevent not only this error but a whole bunch of other difficulties: **Don't use golbal variables. Period.** – Arne Mertz Feb 26 '13 at 14:17
  • Wow that was a fast response. Thank you!! – brimaa Feb 26 '13 at 14:48
2

Everywhere you're including Chart.h, you're effectively dropping variables t, l, and d into those objects. Declare them as extern, then define them in Chart.cpp

mark
  • 5,269
  • 2
  • 21
  • 34
0

I've had the exact same problem and I found a workarroud.

chart.h becomes:

#pragma once

#include "foo.h"

class Chart{
    static int t;
    static foo l;
    class Bars
    {
        static int d;
    };
};

and define the variables in chart.cpp

int Chart::t;
foo Chart::l;
int Chart::Bars::d;

Ugly, I know, but at least the syntax is the same wherever you need to use the vars.

This way only ONE .obj file is created containing the variables which prevents the multiple definition erros.
I haven't tried if you can declare a static variable on a namespace which could solve the problem.

Edit:

P.S. this solution gives some weird errors on msvc, as if every time it is included, sections of the code reference differente variables

Tested on my own program the static-inside-namespace and it seems to work.
Example.h:

namespace sdl{
    static SDL_Surface* screen;

    static int xres = 640;
    static int yres = 480;
    static int bpp  = 32;
    static int flags = SDL_ASYNCBLIT;

};
NeonMan
  • 623
  • 10
  • 24