Viku
Viku

Reputation: 2973

How to avoid linker error

Inside General.h

#ifndef GENERAL
#define GENERAL
namespace counternamespace{
    int upperbound;
    int lowerbound;
}
#endif

Inside Analyzer.h

#ifndef ANALYZER
#define ANALYZER
#include"General.h"

class Analyzer
{
public :
     int var ;
     int func();
};
#endif

Inside Test.h

#ifndef TEST
#define TEST
#include"Analyzer.h" //Error
class Test2
{
public:
    Test2(void);

public:
    ~Test2(void);
};
#endif

In the above code when I don't add Analyzer inside Test.h everything is working fine. But after adding its showing the following linker error.

1>Test2.obj : error LNK2005: "int counternamespace::lowerbound" (?lowerbound@counternamespace@@3HA) already defined in Analyzer.obj
2>Test2.obj : error LNK2005: "int counternamespace::upperbound" (?upperbound@counternamespace@@3HA) already defined in Analyzer.obj

I have added the #ifndef/#endif. Then where I am doing the mistake? Can anyone please let me know?

Upvotes: 0

Views: 667

Answers (3)

Viku
Viku

Reputation: 2973

Inside General.h

#ifndef GENERAL
#define GENERAL
namespace counternamespace{
    extern int upperbound;
    extern int lowerbound;
}
#endif

Inside General.cpp

#include"General.h"
using namespace counternamespace ;
int counternamepace::upperbound = 12;
int counternamepace::lowerbound = 12;

Then do whatever needed .

Upvotes: 1

Barney Szabolcs
Barney Szabolcs

Reputation: 12514

Yeah, Alok has right. You presumably have Analyser.cpp and Test2.cpp, both are different compilation units. When you call

g++ Analyser.cpp Test2.cpp

the compiler actually makes Analyser.obj and Test2.obj separately and links them together. When the compiler tries to link Analyser.obj and Test2.obj together it realises that the two variables in Test2.obj are present in Analyser.obj too.

Your #define directives do not work since they are present only in a single compilation unit, so General.h is included both in Analyser.obj and Test2.obj.

To avoid such duplicates, the solution is wrapping your namespace variables around with a function. It goes like this:

Inside General.h

#ifndef GENERAL
#define GENERAL
namespace counternamespace{
    int& upperbound();
    int& lowerbound();
}
#endif

inside General.cpp

#include "General.h"
namespace counternamespace{
  int& upperbound(){static int local; return local;}
  int& lowerbound(){static int local; return local;}
}

So you can say now

counternamespace::upperbound()=3;
counternamespace::lowerbound()=1;

and it means the same as you would have said

counternamespace::upperbound = 3;
counternamespace::lowerbound = 1;

don't worry, the compiler will optimise away the function call so there is no overhead either.

Upvotes: 2

Alok Save
Alok Save

Reputation: 206508

You should not define any variables in header files.
A copy of the variables gets created in each translation unit When you include the header file in other files, thus violating the one definition rule and resulting in linking errors.

Upvotes: 1

Related Questions