This question already has answers here:
Undefined reference to static class member
(9 answers)
What is an undefined reference/unresolved external symbol error and how do I fix it?
(39 answers)
Closed 8 years ago.
When I try to compile this code, why does g++ report an error?
class A {
private:
static A* Aptr[5];
public:
static int A_count;
A() {
Aptr[A_count] = this;
}
};
int A::A_count = 0;
int main() {
A a_;
A b_;
return 0;
}
/tmp/ccrp4BGg.o: In function `A::A()':
try.cpp:(.text._ZN1AC2Ev[_ZN1AC5Ev]+0x18): undefined reference to `A::Aptr'
collect2: error: ld returned 1 exit status
Explanation
You have only declared your static data-member named A::Aptr, but in order to use it, as you are inside the constructor of A, you must provide a definition.
The linker diagnostic might say undefined reference, which might be hard to relate to a missing definition, but it's talking about its internal mapping of names and storage location.
In other words; the linker is unable to find a a reference (ie. entry) for the location where A::Aptr is stored, which makes sense: Without a definition you haven't given A::APtr any storage to use.
Solution
You've already provided both a declaration (2), and a definition (4) for A::A_count, if you do the same for A::APtr you will be all set.
class A {
private:
static A* Aptr[5]; // (1), declaration
public:
static int A_count; // (2), declaration
A() {
Aptr[A_count] = this;
}
};
A* A::APtr[5]; // (3), definition <-- previously missing!
int A::A_count = 0; // (4), definition
Note: You are only asking about the linker error, but I'm guessing you mean to increment A_count upon constructing an object of type A, something which you are currently not doing.
You need to define it outside the class, just like any other static variable:
Because it is static you need to define Aptr outside of the class, right now you have only declared it but not defined and initialized it. This means that the linker can't find it. Also do you want to increment A_count?:
class A {
private:
static A* Aptr[5];
public:
static int A_count;
A() {
Aptr[A_count] = this;
A_count++; //I presume you want to do something like this too
}
};
int A::A_count = 0;
A* A::Aptr[5] = { nullptr }
int main() {
A a_;
A b_;
return 0;
}
class A {
private:
static A* Aptr[5];
public:
static int A_count;
A() {
Aptr[A_count] = this;
}
//static ctor
static A(){
Aptr=new A[5];
A_count=0;
}
};
int main() {
A a_;
A b_;
return 0;
}
Related
I've been looking for an answer to this for several hours. Even though I have a workaround I'd like to understand the problem. I get an undefined reference error when linking the following:
.h:
class Test
{
public:
class Class1
{
public:
Class1(int i);
int x;
void Inc();
};
static Class1 one;
static int F1();
};
.cpp:
#include "Test.h"
Test::Class1 one(0);
void Test::Class1::Inc()
{
x++;
}
Test::Class1::Class1(int i)
{
x = i;
}
int Test::F1()
{
//extern Test::Class1 one;
one.Inc();
return one.x;
}
I get an undefined reference to Test:one in the F1 function. If I add the extern Test::Class1 one it seems to work. Why is this necessary?
This is a little confusing due to the nested class, but it's as simple as:
Test::Class1 Test::one(0);
The following statement in your code, just defines a global objet one that happens to be of a nested type: Test::Class1 :
Test::Class1 one(0);
If it wasn't of a nested type, you'd immediately have noticed the missing qualifier ;-)
This question already has answers here:
Should a const static variable be initialized in a c++ header file?
(4 answers)
Closed 9 years ago.
I am going to get right to the point:
//ComponentHolder.h
template<class Holder, uint ID>
class TemplateComponentHolder : public ComponentHolderInterface {
protected:
std::vector<ComponentType*> mComponents;
public:
TemplateComponentHolder() : ComponentHolderInterface(ID) {}
static const uint getStaticID() { return ID; }
};
class ConcereteComponentHolder1 : public TemplateClassHolder<ComponentType, 1000> {
public:
inline void print() { std::cout << "test"; }
};
//World.h
class World {
private:
std::map<uint, ComponentHolderInterface*> mHolders;
public:
template<class Holder> Holder * getHolder() {
auto i = mHolders.find(Holder::getStaticID());
if(i != mHolders.end())
return static_cast<Holder*>((*i));
return NULL;
}
/* ... */
};
//Main code
int main() {
World * world = new World;
world->addHolder(new ConcerteComponentHolder1);
world->getHolder<ConcreteComponentHolder1>()->print();
}
I get unresolved external symbol error. Says cannot resolve "ConcereteComponentHolder1::ID". If I change the static variable to non const and add it to a source file:
//ComponentHolder.cpp
uint ConcreteComponentHolder1::ID = 1000;
There is no problem. It makes sense why the latter one must be defined explicitly. But when I am using const, I have to define it in the header. Getting a linker error when using const just doesn't make sense. Is it because of the template function being generated in the header? Or is it something else?
Placing a variable declaration together with an initialiser in the class declaration dies not actually constitute a definition. You can get away without the definition as long as you only ever take it's value and never try to use it as a reference.
'find' takes a reference to the value as an argument. This means you need an actual variable defined somewhere to take a reference to it.
You might also like to read this SO question: Defining static const integer members in class definition
This question already has answers here:
What is an undefined reference/unresolved external symbol error and how do I fix it?
(39 answers)
Closed 9 years ago.
Let's say I have a .hpp file containing a simple class with a public static method and a private static member/variable.
This is an example class:
class MyClass
{
public:
static int DoSomethingWithTheVar()
{
TheVar = 10;
return TheVar;
}
private:
static int TheVar;
}
And when I call:
int Result = MyClass::DoSomethingWithTheVar();
I would expect that "Result" is equal to 10;
Instead I get (at line 10):
undefined reference to `MyClass::TheVar'
Line 10 is "TheVar = 10;" from the method.
My question is if its possible to access a private static member (TheVar) from a static method (DoSomethingWithTheVar)?
The response to your question is yes ! You just missed to define the static member TheVar :
int MyClass::TheVar = 0;
In a cpp file.
It is to respect the One definition rule.
Example :
// Myclass.h
class MyClass
{
public:
static int DoSomethingWithTheVar()
{
TheVar = 10;
return TheVar;
}
private:
static int TheVar;
};
// Myclass.cpp
#include "Myclass.h"
int MyClass::TheVar = 0;
I would like to have a static member variable keep track of the amount of objects that have been made. Like so:
class test{
static int count = 0;
public:
test(){
count++;
}
}
That doesn't work because, according to VC++, a member with an in-class initializer must be constant. So I looked around and apparently you're supposed to do:
test::count = 0;
Which would be great, but I want count to be private.
edit:
Oh boy, I just realized I need to do:
int test::count = 0;
I had seen something just do test::count = 0, so I assumed you wouldn't have to declare type again.
I'd like to know if there's a way to do this inside the class though.
edit2:
What I'm using:
class test{
private:
static int count;
public:
int getCount(){
return count;
}
test(){
count++;
}
}
int test::count=0;
Now it's saying: 'test' followed by 'int' is illegal (did you forget a ';'?)
edit3:
Yup, forgot a semicolon after the class definition. I'm not used to having to do that.
Put
static int count;
In your header in the class definition, and
int test::count = 0;
In the .cpp file. It will still be private (if you leave the declaration in the header in the private section of the class).
The reason you need this is because static int count is a variable declaration, but you need the definition in a single source file so that the linker knows what memory location you're referring to when you use the name test::count.
Initialization of static variable within a function is allowed so a solution can be something like this
class test
{
private:
static int & getCount ()
{
static int theCount = 0;
return theCount;
}
public:
int totalCount ()
{
return getCount ();
}
test()
{
getCount () ++;
}
};
in general using this technique it is possible to work around the C++ limitation regarding static member initialization in the declaration.
static class members must be defined (and potentially initialized) at namespace scope, member access rules do not apply.
Failed to link up following two files, when I remove the "static" keyword, then it is okay. Tested with g++.
Check with readelf for the object file, the static member seems is exported as a global object symbol... I think it should be a local object ...?
static1.cpp
class StaticClass
{
public:
void setMemberA(int m) { a = m; }
int getMemberA() const { return a; }
private:
static int a;
};
int StaticClass::a = 0;
void first()
{
StaticClass statc1;
static1.setMemberA(2);
}
static2.cpp
class StaticClass
{
public:
void setMemberA(int m) { a = m; }
int getMemberA() const { return a; }
private:
static int a;
};
int StaticClass::a = 0;
void second()
{
StaticClass statc1;
static1.setMemberA(2);
}
With error infoļ¼
/tmp/ccIdHsDm.o:(.bss+0x0): multiple
definition of `StaticClass::a'
It seems like you're trying to have local classes in each source file, with the same name. In C++ you can encapsulate local classes in an anonymous namespace:
namespace {
class StaticClass
{
public:
void setMemberA(int m) { a = m; }
int getMemberA() const { return a; }
private:
static int a;
};
int StaticClass::a = 0;
} // close namespace
void first()
{
StaticClass statc1;
static1.setMemberA(2);
}
The following is a definition of the static data member. It has to occur only in one file that's compiled and then linked.
int StaticClass::a = 0;
If you have multiple such definitions, it is as if you had multiple functions called first. They will clash and the linker will complain.
I think you are mistaking static members with static applied to namespace scope variables. At the namespace level, static gives the variable or reference internal linkage. But at the class scope level (when applied to a member), it will become a static member - one that is bound to the class instead of each object separately. That then has nothing to do with the C meaning of "static" anymore.
The statement
int StaticClass::a = 0;
actually allocates storage for the variable, this is why it should be only written once.
As for your remark, you are probably confusing two different uses of the static keyword. In C static used to mean "use internal linkage", this means that the name of a variable or function would not be seen outside the translation unit where it was defined.
In classes, static is used to define class members, that is variables or methods that don't refer to a specific instance of the class. In this case the storage for a static variable must be allocated somewhere (as it is not part of any instance), but only in one place of course.
StaticClass needs a place to store a, a static variable that will be shared by all class instances - there are two lines that do so, one in each file. Removing one will fix the linker error.