Could someone please advise?
If const in C++ defaults to internal linkage, why do I get multiple definition errors in the code below?
First, the file dem.h:
#ifndef _DEM_H_
#define _DEM_H_
class Dem {
public:
static const int i;
};
const int Dem::i = 10;
#endif
Them imp1.cpp:
#include "dem.h"
#include <iostream>
using namespace std;
extern int foo();
int main() {
cout << foo() << endl;
}
and imp2.cpp:
#include "dem.h"
int foo() {
return Dem::i ;
}
I compile with the following command and results:
$ g++ imp1.cpp imp2.cpp
/tmp/ccmGt0OY.o:imp2.cpp:(.rdata+0x0): multiple definition of `Dem::i'
/tmp/cc5sN7dz.o:imp1.cpp:(.rdata+0x0): first defined here
collect2: ld returned 1 exit status
From C++11 [basic.link], paragraph 5:
In addition, a member function, static data member, a named class or enumeration of class scope, or an unnamed class or enumeration defined in a class-scope typedef declaration such that the class or enumeration has the typedef name for linkage purposes (7.1.3), has external linkage if the name of the class has external linkage.
Because your class has external linkage, so does your static data member.
Its static to the compilation unit. You are compiling in two steps - first impl1.cpp and then impl2.cpp - and in each unit the compiler instantiates the static data member. When the linker then tries to link the two associated object files together, it sees two different definitions for the same symbol , and so you get a multiple definition error.
Related
So I have a file called test.cpp
class Entity
{
int c = 0;
int b = 0;
int d = 5;
};
And then another called main.cpp
#include<iostream>
#include<vector>
#include<algorithm>
class Entity
{
int a = 5;
int b = 0;
};
int main()
{
}
Why does this link and work just fine? Doesn't the linker see that there are 2 classes with the same name and different data members? Also would these be considered class definitions? If I wanna declare this class in a header file I would just do what I did here right? Even though I'm technically defining variables it's still just a class declaration right..?
It is an ill-formed program.
As the class definition has external linkage then each definition of the class shall consist of the same sequence of tokens.
On the other hand, as neither code from the translation unit test.cpp is used the linker can exclude it from the final exe file.
Very simply put:
I have a class that consists mostly of static public members, so I can group similar functions together that still have to be called from other classes/functions.
Anyway, I have defined two static unsigned char variables in my class public scope, when I try to modify these values in the same class' constructor, I am getting an "unresolved external symbol" error at compilation.
class test
{
public:
static unsigned char X;
static unsigned char Y;
...
test();
};
test::test()
{
X = 1;
Y = 2;
}
I'm new to C++ so go easy on me. Why can't I do this?
If you are using C++ 17 you can just use the inline specifier (see https://stackoverflow.com/a/11711082/55721)
If using older versions of the C++ standard, you must add the definitions to match your declarations of X and Y
unsigned char test::X;
unsigned char test::Y;
somewhere. You might want to also initialize a static member
unsigned char test::X = 4;
and again, you do that in the definition (usually in a CXX file) not in the declaration (which is often in a .H file)
Static data members declarations in the class declaration are not definition of them.
To define them you should do this in the .CPP file to avoid duplicated symbols.
The only data you can declare and define is integral static constants.
(Values of enums can be used as constant values as well)
You might want to rewrite your code as:
class test {
public:
const static unsigned char X = 1;
const static unsigned char Y = 2;
...
test();
};
test::test() {
}
If you want to have ability to modify you static variables (in other words when it is inappropriate to declare them as const), you can separate you code between .H and .CPP in the following way:
.H :
class test {
public:
static unsigned char X;
static unsigned char Y;
...
test();
};
.CPP :
unsigned char test::X = 1;
unsigned char test::Y = 2;
test::test()
{
// constructor is empty.
// We don't initialize static data member here,
// because static data initialization will happen on every constructor call.
}
in my case, I declared one static variable in .h file, like
//myClass.h
class myClass
{
static int m_nMyVar;
static void myFunc();
}
and in myClass.cpp, I tried to use this m_nMyVar. It got LINK error like:
error LNK2001: unresolved external symbol "public: static class...
The link error related cpp file looks like:
//myClass.cpp
void myClass::myFunc()
{
myClass::m_nMyVar = 123; //I tried to use this m_nMyVar here and got link error
}
So I add below code on the top of myClass.cpp
//myClass.cpp
int myClass::m_nMyVar; //it seems redefine m_nMyVar, but it works well
void myClass::myFunc()
{
myClass::m_nMyVar = 123; //I tried to use this m_nMyVar here and got link error
}
then LNK2001 is gone.
Since this is the first SO thread that seemed to come up for me when searching for "unresolved externals with static const members" in general, I'll leave another hint to solve one problem with unresolved externals here:
For me, the thing that I forgot was to mark my class definition __declspec(dllexport), and when called from another class (outside that class's dll's boundaries), I of course got the my unresolved external error.
Still, easy to forget when you're changing an internal helper class to a one accessible from elsewhere, so if you're working in a dynamically linked project, you might as well check that, too.
When we declare a static variable in a class, it is shared by all the objects of that class. As static variables are initialized only once they are never initialized by a constructor. Instead, the static variable should be explicitly initialized outside the class only once using the scope resolution operator (::).
In the below example, static variable counter is a member of the class Demo. Note how it is initialized explicitly outside the class with the initial value = 0.
#include <iostream>
#include <string>
using namespace std;
class Demo{
int var;
static int counter;
public:
Demo(int var):var(var){
cout<<"Counter = "<<counter<<endl;
counter++;
}
};
int Demo::counter = 0; //static variable initialisation
int main()
{
Demo d(2), d1(10),d3(1);
}
Output:
Count = 0
Count = 1
Count = 2
In my case, I was using wrong linking.
It was managed c++ (cli) but with native exporting. I have added to linker -> input -> assembly link resource the dll of the library from which the function is exported. But native c++ linking requires .lib file to "see" implementations in cpp correctly, so for me helped to add the .lib file to linker -> input -> additional dependencies.
[Usually managed code does not use dll export and import, it uses references, but that was unique situation.]
In a big project, I have a .h file which defines a lot of constants within a namespace. Introducing const char* constants results in linker errors complaining of multiple definitions.
ex.h
#include <string>
namespace Dv
{
const int MAX = 10;
const std::string NAME = "bobo";
const char* NAME2 = "fred"; // <-- ERROR: multiple definition of `Dv::NAME2'
}
exA.cpp
#include "ex.h"
void aFunction() { printf("this is aFunction\n"); }
exB.cpp
#include "ex.h"
void aFunction(void);
int main(int argc, char **argv)
{
aFunction();
return 0;
}
Compile and Link
g++ -c exA.cpp
g++ -c exB.cpp
g++ exA.o exB.o -o ex
exB.o:(.data+0x0): multiple definition of `Dv::NAME2'
exA.o:(.data+0x0): first defined here
collect2: ld returned 1 exit status
The linker error happens if NAME2 is included in the .h file. Why?
If MAX is also a POD (like char[]?), why does the linker not complain of multiple int MAX definitions? (or multiple std::string NAME definitions for that matter?)
I don't understand what's special about char[] in this situation.
Thanks
According to the C++ Standard (3.5 Program and linkage)
3 A name having namespace scope (3.3.6) has internal linkage if it is
the name of
— a non-volatile variable that is explicitly declared const or constexpr and neither explicitly declared extern nor previously
declared to have external linkage; or
and
4 An unnamed namespace or a namespace declared directly or indirectly
within an unnamed namespace has internal linkage. All other
namespaces have external linkage. A name having namespace scope that
has not been given internal linkage above has the same linkage as the
enclosing namespace if it is the name of — a variable; or
In this namespace definition
namespace Dv
{
const int MAX = 10;
const std::string NAME = "bobo";
const char* NAME2 = "fred"; // <-- ERROR: multiple definition of `Dv::NAME2'
}
(the only) variable NAME2 is not a constant and hence has external linkage.
You could make it as having internal linkage defining it for example with keyword static. For example
namespace Dv
{
const int MAX = 10;
const std::string NAME = "bobo";
static const char* NAME2 = "fred";
}
Or could define it as a constant
namespace Dv
{
const int MAX = 10;
const std::string NAME = "bobo";
const char * const NAME2 = "fred";
}
How can achieve external linkage for class static functions when the compiler thinks the code is local linkage or inline?
Consider three files:
traits.h:
template <typename T>
struct Traits
{
static int InlineFunction(T);
static int Function(T);
};
traitsimp.cpp:
#include "traits.h"
template <>
struct Traits<int>
{
static int InlineFunction(int) { return 42; }
static int Function(int);
};
int Traits<int>::Function(int i) { return i; }
main.cpp:
#include "traits.h"
int main()
{
int result = Traits<int>::Function(5);
result = Traits<int>::InlineFunction(result);
return 0;
}
When compiled receives:
$ g++ traitsimp.cpp main.cpp -o traitstest
/tmp/cc6taAop.o: In function `main':
main.cpp:(.text+0x1b): undefined reference to `Traits<int>::InlineFunction(int)'
collect2: ld returned 1 exit status
How do I convince the compiler to give InlineFunction external linkage while still writing the function within the class definition?
I think you need to decide whether to have external linkage and define out of line or keep it inline and effectively just have internal linkage. Is there a reason not to define your Traits<int> in a header? Note that the full specialization is no longer a template, so there is really no difference to how it is handled versus a non-templated function.
Edited: Tried this in VS2010, and it may still not suit, but you could put code in traitsimp.cpp that takes the address of the method:
auto getAddress = &Traits<int>::InlineFunction;
This forces the method to get an address. I'm a bit rusty on whether this behaviour would be standard or not.
Very simply put:
I have a class that consists mostly of static public members, so I can group similar functions together that still have to be called from other classes/functions.
Anyway, I have defined two static unsigned char variables in my class public scope, when I try to modify these values in the same class' constructor, I am getting an "unresolved external symbol" error at compilation.
class test
{
public:
static unsigned char X;
static unsigned char Y;
...
test();
};
test::test()
{
X = 1;
Y = 2;
}
I'm new to C++ so go easy on me. Why can't I do this?
If you are using C++ 17 you can just use the inline specifier (see https://stackoverflow.com/a/11711082/55721)
If using older versions of the C++ standard, you must add the definitions to match your declarations of X and Y
unsigned char test::X;
unsigned char test::Y;
somewhere. You might want to also initialize a static member
unsigned char test::X = 4;
and again, you do that in the definition (usually in a CXX file) not in the declaration (which is often in a .H file)
Static data members declarations in the class declaration are not definition of them.
To define them you should do this in the .CPP file to avoid duplicated symbols.
The only data you can declare and define is integral static constants.
(Values of enums can be used as constant values as well)
You might want to rewrite your code as:
class test {
public:
const static unsigned char X = 1;
const static unsigned char Y = 2;
...
test();
};
test::test() {
}
If you want to have ability to modify you static variables (in other words when it is inappropriate to declare them as const), you can separate you code between .H and .CPP in the following way:
.H :
class test {
public:
static unsigned char X;
static unsigned char Y;
...
test();
};
.CPP :
unsigned char test::X = 1;
unsigned char test::Y = 2;
test::test()
{
// constructor is empty.
// We don't initialize static data member here,
// because static data initialization will happen on every constructor call.
}
in my case, I declared one static variable in .h file, like
//myClass.h
class myClass
{
static int m_nMyVar;
static void myFunc();
}
and in myClass.cpp, I tried to use this m_nMyVar. It got LINK error like:
error LNK2001: unresolved external symbol "public: static class...
The link error related cpp file looks like:
//myClass.cpp
void myClass::myFunc()
{
myClass::m_nMyVar = 123; //I tried to use this m_nMyVar here and got link error
}
So I add below code on the top of myClass.cpp
//myClass.cpp
int myClass::m_nMyVar; //it seems redefine m_nMyVar, but it works well
void myClass::myFunc()
{
myClass::m_nMyVar = 123; //I tried to use this m_nMyVar here and got link error
}
then LNK2001 is gone.
Since this is the first SO thread that seemed to come up for me when searching for "unresolved externals with static const members" in general, I'll leave another hint to solve one problem with unresolved externals here:
For me, the thing that I forgot was to mark my class definition __declspec(dllexport), and when called from another class (outside that class's dll's boundaries), I of course got the my unresolved external error.
Still, easy to forget when you're changing an internal helper class to a one accessible from elsewhere, so if you're working in a dynamically linked project, you might as well check that, too.
When we declare a static variable in a class, it is shared by all the objects of that class. As static variables are initialized only once they are never initialized by a constructor. Instead, the static variable should be explicitly initialized outside the class only once using the scope resolution operator (::).
In the below example, static variable counter is a member of the class Demo. Note how it is initialized explicitly outside the class with the initial value = 0.
#include <iostream>
#include <string>
using namespace std;
class Demo{
int var;
static int counter;
public:
Demo(int var):var(var){
cout<<"Counter = "<<counter<<endl;
counter++;
}
};
int Demo::counter = 0; //static variable initialisation
int main()
{
Demo d(2), d1(10),d3(1);
}
Output:
Count = 0
Count = 1
Count = 2
In my case, I was using wrong linking.
It was managed c++ (cli) but with native exporting. I have added to linker -> input -> assembly link resource the dll of the library from which the function is exported. But native c++ linking requires .lib file to "see" implementations in cpp correctly, so for me helped to add the .lib file to linker -> input -> additional dependencies.
[Usually managed code does not use dll export and import, it uses references, but that was unique situation.]