Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
In robots.hpp I have a class, robots. I want each robot to have a pointer to another robot, the one that was declared last. I also want each to have a unique id. For this I have a variable that counts the number of robots.
It seems that I can't initialise my static variables in the class definition. I looked up how to solve that, and found something recommending initialising them in robots.cpp. However, that gives me an error saying that they are protected, and so I can't do that. So now I have a function that is called by the constructor only once, at the beginning.
However, that is giving me an error saying that I can't do that, because they haven't been defined yet.
The class definition in robots.hpp:
class robot
{
public:
///initialiser.
robot();
[...]
///initialises all robots
void initrobots();
///id of robot
const uint_least8_t id=NumOfRobots++;
static bool hasBeenInitialised;
protected:
///number of robots.
static uint_least8_t NumOfRobots;
///pointer to the next robot that needs pointing to.
static robot* poiRobot;
[...]
///pointer to next robot
robot* nextRobot;
};
robots.cpp:
bool robot::hasBeenInitialised=false;
void robot::initrobots(){
poiRobot=NULL;
NumOfRobots=0;
}
robot::robot(){
if(!hasBeenInitialised){
initrobots();
hasBeenInitialised=true;
}
[...]
}
The code that generates this error is this:
#include <cstdint>
#include <cstdlib>
class robot
{
public:
///initialiser.
robot();
//[...]
///initialises all robots
void initrobots();
///id of robot
const uint_least8_t id=NumOfRobots++;
static bool hasBeenInitialised;
protected:
///number of robots.
static uint_least8_t NumOfRobots;
///pointer to the next robot that needs pointing to.
static robot* poiRobot;
//[...]
///pointer to next robot
robot* nextRobot;
};
bool robot::hasBeenInitialised=false;
void robot::initrobots(){
poiRobot=NULL;
NumOfRobots=0;
}
robot::robot(){
if(!hasBeenInitialised){
initrobots();
hasBeenInitialised=true;
}
}
int main(){
return 0;
}
If I compile it it doesn't complain, but it does complain if I build it (using geany to do the things separately, c++11 standard(otherwise cstdint complains))
I would like the code to make poiRobot a pointer to null, and NumofRobots equal to 0.
You should be able to get rid of static bool hasBeenInitialised; and bool robot::hasBeenInitialised=false; as well as your initialization function and just declare uint_least8_t robot::NumOfRobots = 0; and robot* robot::poiRobot = nullptr directly in your cpp file. This way they initialize themselves to 0 and null automatically. As mentioned in the comments this is valid, protected static variables should be able to be defined in the source file in this manner.
Edit: In regards to the code you posted in your edit, it looks like you are never defining robot::poiRobot and robot::NumRobots. Did you try the code I posted above?
Basically, each cpp file in your project must be compiled into a translation unit by the compiler. Then the linker comes through and takes all of the translation unit's and links them together. Any cpp file that sees your robot class will see that you've promised that those 2 variables exist somewhere, and therefore when you use them it will allow it (as far is it is concerned, they exist and are good to go). When the linker comes along it will see references to those variables and try to find which translation unit they were defined in so that it can do its job (link everything together). At this point, it won't see a definition in any translation unit, and that is why it gives you that error.
uint_least8_t robot::NumOfRobots = 0; and robot* robot::poiRobot = nullptr are the definitions you are looking for, and should go in your cpp file. If after using those you get another error about them being protected as you had hinted at earlier, post that code so we can see why that is happening.
Edit 2 in regards to "It seems that I can't initialise my static variables in the class definition.": When you put that definition in the header file, each cpp file that includes your header will define it's own version of that variable. When the linker goes to link everything it will see multiple definitions in different translation units for the same variable and that violates the "One Definition Rule" in C++ (ODR). That is why it will give you an error. It is correct to put it in robots.cpp so only 1 translation unit (robots.cpp in this case) will have the definition. Then you have to make sure that robots.cpp is being compiled in your project so that the translation unit is available for the linker... as you could mistakenly just include robots.h in your source files, but never tell the compiler to compile robots.cpp.
Related
There doesn't seem to be a clear, concise example of real word use of a public static variable in C++ from multiple files on StackOverflow.
There are many examples showing how to use static variables in a single C++ translation unit, and many questions about the precise nature of the various uses of the static keyword, but as a programmer more experienced with C# I found it hard to scrape together what I needed to simply "have a static variable on a class and use it elsewhere" like you would in C# or Java.
Here I will try to demonstrate what I discovered in the most straightforward way. I hope that others will then improve on the answer and give more technical details for those that are interested.
SomeClass.h
In the header file for the class where we want to have a static variable, we just declare it static like we would in C# or Java. Don't try to initialise the variable here; C++ doesn't like that.
class SomeClass
{
public:
static bool some_flag;
};
SomeClass.cpp
In the cpp file for the class, we create the storage for the static variable, just like we would provide the implementation for a member function. Here we can initialise the variable. So far, this is going swimmingly!
#include "SomeClass.h"
bool SomeClass::some_flag = true;
SomeOtherClass.cpp
Here is where I ran into problems. If we try to just access SomeClass::some_flag from elsewhere (which, let's face it, is probably the reason you wanted a public static variable in the first place), the linker will complain that it doesn't know where it lives. We've told the compiler that the static variable exists, so the compiler is happy. The problem is that in this other translation unit we've never specified where that static variable is stored. You may be tempted to try redeclaring the storage, and hoping the linker resolves them both as "the some_flag I declared in SomeClass.h", but it won't. It will complain that you've given the variable two homes, which of course is not what you meant.
What we need to do is to tell the linker that the storage for some_flag lives elsewhere, and that it will be found once we try to put all the translation units together at link time. We use the extern keyword for this.
#include "SomeOtherClass.h"
#include "SomeClass.h"
extern bool SomeClass::some_flag;
void SomeOtherClass::SomeOtherFunction()
{
SomeClass::some_flag = true;
};
Voila! The compiler is happy, the linker is happy, and hopefully the programmer is also happy.
I now leave this open for a discussion on how I should not have used a public variable, could have just passed an instance of SomeClass through the 87 layers of code that's between it and the usage, should have used some feature coming in C++23, should have used boost::obscurething etc. etc.
I do however welcome any alternative approaches to this fundamental problem that are true to the usage I've demonstrated here.
Here is where I ran into problems. If we try to just access SomeClass::some_flag from elsewhere [...], the linker will complain that it doesn't know where it lives.
The linker won't complain, as long as you link with the translation unit that defines the variable (SomeClass.cpp).
extern bool SomeClass::some_flag;
This declaration is neither allowed, nor is it necessary. The class definition that contains the variable declaration is sufficient for the compiler, and the variable definition in SomeClass.cpp is sufficient for the linker. Demo
Don't try to initialise the variable here; C++ doesn't like that.
I do however welcome any alternative approaches to this fundamental problem
You could simply use an inline variable (since C++17):
class SomeClass
{
public:
inline static bool some_flag = true;
The answer, in summary form, for people who just want the code so they can get back to work:
SomeClass.h
#pragma once
class SomeClass
{
public:
static bool some_flag;
};
SomeClass.cpp
#include "SomeClass.h"
bool SomeClass::some_flag = true;
SomeOtherClass.cpp
#include "SomeOtherClass.h"
#include "SomeClass.h"
extern bool SomeClass::some_flag;
void SomeOtherClass::SomeOtherFunction()
{
SomeClass::some_flag = true;
}
First I'll try to describe the current situation:
I am adapting an existing code base for our uses and in some instances a .h/.cpp file contains multiple class definitions. We cannot change the existing public interface of the API without major modifications to other portions of the code that we would rather avoid at this time.
I have found the need for constant values that are used by more than one class (in the same .cpp file and nowhere else) and therefore cannot be defined as a class-specific constant. The only way I know to do this is to define the constants externally from any class (but still in the .cpp file) and reference them as needed.
I have done this and the code compiles and links, but when I go to run a test program on the code it fails with an error that appears to be related to the constant value I have defined. I get the impression that when the code executes, the constant has not actually been defined and the code blows up because of that.
I don't have a lot of experience writing C++ code and wonder if I'm doing this the wrong way. I will include code snippets below to try to illustrate what I'm doing.
In DateTime.cpp (currently nothing defined in DateTime.h for DATE_FORMAT_REGEX):
...
#include <boost/regex.hpp>
static const boost::regex DATE_FORMAT_REGEX("[0-9]{4}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])(Z|([+|-]([01][0-9]|2[0-4]):[0-5][0-9]))?");
// Other class method implementations ...
bool our_ns::Date::parse_string(const std::string& s)
{
// Validate string against regex.
bool valid = boost::regex_match(s, DATE_FORMAT_REGEX);
if (valid) {
...
}
}
...
The call to regex_match is what fails. All of the classes, by the way are defined within a namespace in the header file.
It would appear the constant is not being initialized. What do I need to do to initialize these values? Based upon what I've described, is there a better way to do this?
[Update: 6/9/15 12:52 EDT]
Actually, I am relaying information witnessed by another developer in the organization. He verified in a debugger that the regex item was null when he reached the line where it blows up. He also mentioned that when he did some experimentation and moved the definitions from the .cpp to the .h file, the error did not recur. Beyond that, I don't know if things were executing properly.
The correct way is to not defined these as static const but rather as const. These are constants, they do not need static linkage. If you're doing it to avoid the global namespace, const variables have implicit compilation unit scoping anyway.
If Date::parse_string is called from a Date constructor and the Date object is static and initialized in a different compilation unit (C++ file) then it could be an issue related to static variable initialization order. In this case the order of initialization of variables is not defined so the Date object might be initialized before DATE_FORMAT_REGEX and as a result parse_string is called before DATE_FORMAT_REGEX is initialized. You can fix it by moving DATE_FORMAT_REGEX to the Date class definition.
This is likely a result of initialization order, a well-known issue that one could run into.
It has been described in books, such as C++ FAQs in detail for a very long time. Here is a quick reference:
https://isocpp.org/wiki/faq/ctors#static-init-order
Basically, there is no guaranteed order in which static variables must initialize. This creates situations where you could run into an error, when the "second" object makes use of the "first", but, "first" hasn't been initialized. Please note that "first" and "second" are interchangeable, therein lies the crux of the problem.
In fact, the more dangerous situation is a latent bug, where things continue to work until one day when they don't - usually, induced by a new compiler version or some such change.
It is better to get out of this dependency altogether. You don't seem to need to static here. If the goal is to limit visibility of the variable, then use anonymous namespace and place it before any use.
I have a large project which is designed to control and test hardware.
There are 4 device control classes (for interferometers, a piezo-motor, a PXI system, and a nano-positioning controller).
I created a "master" class called MainIO which stores an instance of each of the above classes, in order to perform operations across the range of IO (i.e. move motor and check interferometers). The MainIO header file includes the 4 control classes headers.
I then have a separate "global" hpp/cpp which contains global variables, conversions, ini file operations and so on. This is laid out with namespaces for the types of operation rather than creating a class, i.e. GCONV::someFunction(); and GMAIN::controllerModel;
I need all 4 control classes to have access to conversion and other global operations. I had them all including global.hpp at one point, but I've changed something (I can't think what it could be!) and now it seems that I cannot include global.hpp in ANY of my control class hpp's or cpp's without getting a linker error -
global.obj:-1: error: LNK2005: "class QString GMAIN::controllerModel" (?controllerModel#GMAIN##3VQString##A) already defined in controllers.obj
I'm absolutely certain that I've done something stupid and the solution is staring me in the face, but it's got to the stage where I'm getting so frustrated with it that I cannot see the wood for the trees.
I have discovered what I was doing wrong, and although it is frustratingly simple, it took me a while to find the relevant documentation to discover my error, and so I will answer my own question in the hope of giving someone else an easier time.
It turns out that in global.hpp I was declaring variables within a namespace like this:
namespace GMAIN {
QString controllerModel;
}
Essentially this means that every file that includes global.hpp will include its own definition of QString controllerModel thereby throwing the linker error. Each control class would have its own definition of the same named variable, violating the one definition rule.
To fix this, QString controllerModel needs to be extern'ed. The extern keyword allows a variable to be declared in multiple locations while only having a single definition (and hence not breaking the rule).
So the working code is now:
//in global.hpp
namespace GMAIN {
extern QString controllerModel; //declaration - this is called for each `#include global.hpp`
}
//in global.cpp
namespace GMAIN {
QString controllerModel; //definition - only called once as .cpp is never included
}
Are you defining controllerModel where you should only be declaring it?
http://www.cprogramming.com/declare_vs_define.html
You should export your dll.
Use __declspec(dllexport). You can include __declspec(dllexport) as a macro in your header file and put the macro in the beginning of each and every member function.
For example:
In your Header.h file include
#define MYMACRO __declspec(dllexport);
and in your class
class classname
{
public:
MYMACRO void MYFUNCTION();
MYMACRO void MYFUNCTION2();
};
I am getting very confused in some concepts in c++. For ex: I have following two files
//file1.cpp
class test
{
static int s;
public:
test(){s++;}
};
static test t;
int test::s=5;
//file2.cpp
#include<iostream>
using namespace std;
class test
{
static int s;
public:
test(){s++;}
static int get()
{
return s;
}
};
static test t;
int main()
{
cout<<test::get()<<endl;
}
Now My question is :
1. How two files link successfully even if they have different class definitions?
2. Are the static member s of two classes related because I get output as 7.
Please explain this concept of statics.
They link because the linker knows almost nothing about the C++ language. However, if you do this, you have broken the One Definition Rule, and the behaviour of your program will be undefined. writing invalid code is not a good way of learning C++. Also, you seem to be having a lot of questions about static variables - the concept is really not all that complex - which C++ textbook are you using that does not explain it well?
The classes are (as far as the linker is concerned) identical. get() is just an inline function the linker never sees.
static in a class doesn't limit the member to file scope, but makes it global for all class instances.
[edit:] You'd get an linker error if you would put int test::s=5; into the second file as well.
Static is a strange beast in C++, that has different meanings depending on the context.
In File1.cpp, "static int s" in the class definition indicates that s is a static member, that is, is common to all instances of test.
The "static test t", though, has a different meaning: a static global variable only exists in the compilation unit, and will not be visible by other units. This is to avoid linker confusion if you were using the same name for two different things. In modern C++, one would use anonymous namespaces for this:
namespace
{
test t;
}
This means that t inside File1.cpp and t inside File2.cpp are separate objects.
In File2.cpp, you also defined a static method get: a static method is a method that belongs to the class instead of the instance, and that can only access static members of the class.
A last use of static, that you did not use in your example, is the local static variable. A local static variable is initialised the first time it gets executed, and keeps its value throughout the execution, a bit like a global variable with a local scope:
int add()
{
static value = 0;
value++;
return value;
}
Calling add() repetitively will return 1, then 2, then 3... This local static construct can be useful for local caches for example.
How two files link successfully even if they have different class definitions?
You violated the One Definition Rule (ODR) by defining the same class differently in different translation units. That invokes the dreaded Undefined Behavior. Which means the code is allows to do anything, including, but not limited to, doing what you wanted, formatting your hard disk, or causing an un-accounted for eclipse of the sun.
Note that compilers/linker are not requested to detect ODR violations.
Are the static member s of two classes related because I get output as 7.
Maybe they are, maybe they are not. Really, undefined behavior might do just anything. What you see is just an artifact of however your compiler and linker are implemented.
A likely implementation will happily link all references to test::s to the same instance, but let each translation unit have - and link to - their own t object. (Since the class has only inline functions, the linker most likely never even sees anything of test except for test::s and those t instances.)
Unnice side-effect of how C++ actually works. Use namespaces to make the class names different to outside.
In past I had used the quite burdensome in practice rule: every library and file has to have a private namespace for to avoid such link conflicts. Or put the utility classes right into the main class definition. Anyway: not to pollute global namespace and most importantly ensure uniqueness of names across the whole project. (Writing that now I notice that I used pretty much verbatim the concept from Java.)
My search for equivalent of C's static in C++ was unfruitful...
I'm getting linkage errors of the following type:
Festival.obj : error LNK2019:
unresolved external symbol "public:
void __thiscall Tree::add(class Price &)"
(?add#?$Tree#VPrice####QAEXAAVPrice###Z)
referenced in function
__catch$?AddBand#Festival##QAE?AW4StatusType##HHH#Z$0
I used to think it has to do with try-catch mechanism, but since been told otherwise. This is an updated version of the question.
I'm using Visual Studio 2008, but I have similar problems in g++.
The relevant code:
In Festival.cpp
#include "Tree.h"
#include <exception>
using namespace std;
class Band{
public:
Band(int bandID, int price, int votes=0): bandID(bandID), price(price), votes(votes){};
...
private:
...
};
class Festival{
public:
Festival(int budget): budget(budget), minPrice(0), maxNeededBudget(0), priceOffset(0), bandCounter(0){};
~Festival();
StatusType AddBand(int bandID, int price, int votes=0);
...
private:
Tree<Band> bandTree;
...
};
StatusType Festival::AddBand(int bandID, int price, int votes){
if ((price<0)||(bandID<0)){
return INVALID_INPUT;
}
Band* newBand=NULL;
try{
newBand=new Band(bandID,price-priceOffset,votes);
}
catch(bad_alloc&){return ALLOCATION_ERROR;}
if (bandTree.find(*newBand)!=NULL){
delete newBand;
return FAILURE;
}
bandTree.add(*newBand);
....
}
In Tree.h:
template<class T>
class Tree{
public:
Tree(T* initialData=NULL, Tree<T>* initialFather=NULL);
void add(T& newData);
....
private:
....
};
Interestingly enough I do not have linkage errors when I try to use Tree functions when type T is a primitive type like an int.
Is there Tree.cpp? If there is, maybe you forgot to link it? Where is the implementation of Tree::add?
In addition I don't see where you call Tree::add. I guess it should be inside the try statement, right after the new?
Just a reminder:
For most compilers (i.e. those that practice separate compilation) the implementation of the member functions of a template class has to be visible during the compilation of the source file that uses the template class. Usually people follow this rule by putting the implementation of the member functions inside the header file.
Maybe Tree::add isn't inside the header? Then a possible solution in the discussed case will be to put Tree::add implementation inside the header file.
The difference between regular classes and template classes exists because template classes are not "real" classes - it is, well, a template. If you had defined your Tree class as a regular class, the compiler could have used your code right away. In case of a template the compiler first "writes" for you the real class, substituting the template parameters with the types you supplied. Now, compiler compiles cpp files one by one. He is not aware of other cpp files and can use nothing from other cpp files. Let's say your implementation of Tree:add looks like this:
void Tree::add(T& newData)
{
newData.destroyEverything();
}
It is totally legitimate as long as your T has method destroyEverything. When the compiler compiles Class.cpp it wants to be sure that you don't do with T anything it doesn't know. For example Tree<int> won't work because int doesn't have destroyEverything. The compiler will try to write your code with int instead of T and find out that the code doesn't compile. But since the compiler "sees" only the current cpp and everything it includes, it won't be able to validate add function, since it is in a separate cpp.
There won't be any problem with
void Tree::add(int& newData)
{
newData.destroyEverything();
}
implemented in a separate cpp because the compiler knows that int is the only acceptable type and can "count on himself" that when he gets to compile Tree.cpp he will find the error.
Are you sure the try/catch has anything to do with it? What happens if you simply comment out the try and catch lines, leave the rest of the code as it is, and build that?
It might just be that you're missing the library that defines Tree::add(class Price &) from your link line.
Update: using Tree functions with a primitive type doesn't result in a linking error.
I updated my question in light of some of the things that were said.
As others have stated you need to show the implementation of Treee::add() and tell us how you are linking it.
On an unrelated point, if you are using constructs like:
Band* newBand=NULL;
try{
newBand=new Band(bandID,price-priceOffset,votes);
}
catch(bad_alloc&){return ALLOCATION_ERROR;}
throughout your code, you are frankly wasting your time. The chances of you getting to a point of memory exhaustion in a modern OS are remote and the chances of you doing anything useful after it has happened are roughly zero. You will be much better off simply saying:
Band * newBand = new Band ( bandID, price - priceOffset, votes );
ot possibly:
Band newBand( bandID, price - priceOffset, votes );
and forgetting the exception handling in this case.
You wrote in a comment:
I considered this but the function is part of Tree.h, and I do include it. The function defined is: template void Tree::add(T& newData); We call it the following way: priceTree.add(*newPriceNode); whereas priceTree is Tree, both of which are defined in the cpp file in question.
instead of:
priceTree.add(*newPriceNode);
try:
priceTree.add(newPriceNode); //no "*" before "newPriceNode"
add() takes a reference to a node, not a pointer to a node (according to your definition of Tree).
You're getting linkage errors, not compiler errors. This tells us that the compiler knew what sort of function Tree::add() is, but didn't have a definition. In Tree.h, I see a declaration of the add() function, but not a definition. It looks odd to me; does anybody know where Tree.h came from?
Usually a template class comes with member function definitions in the include file, since the functions have to be instantiated somewhere, and the simplest thing is for the compiler to instantiate when used and let the linker sort it out. If the definitions are in Tree.h, I'd expect everything to work as planned.
So, I'm going to go out on a limb and suggest that the definitions are in a separate file, not linked in, and that there are provisions elsewhere for instantiating for basic types like Tree<int>. This is presumably to streamline compilation, as normally these things are compiled in multiple places, and that takes time.
What you need to do in that case is to find where Tree<int> is instantiated, and add an instantiation for your class.
I could be way off base here, but my explanation does fit the facts you've given.
Edit after first comments:
Templates are somewhat trickier than ordinary functions, which usually isn't a real problem. If the definitions for all the calls were in Tree.h, then Festival.cpp would be able to instantiate Tree<Band> and everything would be cool. That's the usual technique, and you're running into this problem because you're not using it.
When you write a function, it gets compiled, and the linker will find it. Any routine calling that function needs to know the function prototype, so it will know how to call it. When you write a template, you're not writing anything that will go directly into the program, but any use of the template counts as writing all the functions.
Therefore, there has to be some use of Tree<Band> somewhere in your program, for there to be a Tree<Band>::add() function compiled. The definition of Tree<T>::add has to be available to the compiler when Tree<Band> is instantiated, because otherwise the compiler has no idea what to compile. In this case, it's generating the function call, confident that you'll make sure the function is compiled elsewhere.
Therefore, you have to instantiate Tree<Band> inside a file that has access to both the definitions for Tree<T> and Band. This probably means a file that is, or includes, Tree.cpp and includes Festival.h.
The linker is already using Tree.cpp, but Tree.cpp doesn't have Tree<Band> defined in it, so it's meaningless to the linker. Templates are only useful for the compiler, and the linker only operates on what the compiler generated from templates.
The quick way to solve this is to take the definitions from Tree.cpp and put them in Tree.h. That will be likely to increase compilation and link times, unfortunately. The other technique is to instantiate all template uses in Tree.cpp, so that they'll be compiled there.