I have recently encountered a behavior in C++ program that I cannot entirely understand. Let me explain the behavior via simple example.
1. First static library
At the very bottom of hierarchy, I have a static library - lets name it FirstLIB. This library includes two pairs of header/source files. The sample.h header file contains MyClass class definition. Corresponding sample.cpp file contains implementation of this class (its methods). The code is presented below:
sample.h
#ifndef __sample_h
#define __sample_h
namespace SampleNamespace
{
class MyClass
{
int counter;
public:
MyClass();
int GetCounter();
void SetCounter(int value);
};
}
#endif
and sample.cpp
#include <iostream>
#include "sample.h"
namespace SampleNamespace
{
MyClass::MyClass(): counter(0)
{
std::cout << "Inside of MyClass constructor!" << std::endl;
}
int MyClass::GetCounter() { return counter; }
void MyClass::SetCounter(int value) { counter = value; }
}
Onwards, the dvcl.h file declares simple API used to manipulate MyClass object and dvcl.cpp implements this API. It's important to notice that dvcl.cpp file contains definition of MyClass object that is used by the methods of this API. The variable is defines as static so it will be visible only inside of this source file.
dvcl.h
#ifndef _dvcl_h
#define _dvcl_h
void DVCL_Initialize(int counter);
int DVCL_GetCounter();
void DVCL_SetCounter(int value);
#endif
dvcl.cpp
#include "dvcl.h"
#include "sample.h"
static SampleNamespace::MyClass myClass;
void DVCL_Initialize(int counter)
{
myClass.SetCounter(counter);
}
int DVCL_GetCounter()
{
return myClass.GetCounter();
}
void DVCL_SetCounter(int value)
{
myClass.SetCounter(value);
}
2. Second static library
Second static library - lets name it SecondLIB - is even simpler than the first one. It only contains one header/source pair. The dvconference_client.h header declares one function, while dvconference_client.cpp implements this function. dvconference_client.cpp also includes dvcl.h header file (which will trigger compilation of dvcl.cpp source). The code can be found below:
dvconference_client.h
#ifndef __external_file
#define __external_file
int DoSomething();
#endif
dvconference.cpp
#include "dvconference_client.h"
#include "dvcl.h"
int DoSomething()
{
return DVCL_GetCounter();
}
3. Main executable
And finally, the main executable MainEXE includes only one main.cpp file. This source includes dvconference_client.h and dvcl.h headers. The code is presented below:
#include <iostream>
#include "dvconference_client.h"
#include "dvcl.h"
int main()
{
std::cout << DoSomething() << std::endl;
std::cout << DVCL_GetCounter() << std::endl;
return 0;
}
4. My doubts and questions:
If I don't call a function that references myClass object (so DoSomething() or one of DVCL_ functions), the MyClass constructor is not invoked. I expected that myClass object will be instantiated by default as dvcl.cpp is compiled. However, it appears that compiler generates needed statements only if it understand that object is actually used in runtime. Is this really true?
If particular header file (in this case dvcl.h) is included in different sources, the corresponding dvcl.cpp is compiled only once. I remember reading something about this, however I'm not sure that this is really true. Is it actually correct that C++ compiler will compile every source file only once, regardless of how many the corresponding header file is included.
myClass object defined in dvcl.cpp is instantiated only once. If I correctly understand the 2nd point and if dvcl.cpp is compiled only once, then there is nothing to question here.
I hope more experienced colleagues can clear my doubts (and I apologize for very long post).
"static SampleNamespace::MyClass myClass; " is both a declaration and definition. So your constructor is invoked and created. Asm-code to instantiate this is generated at compile-time but this is executed at executable-load-time.
For referenec, stages of compilation
source-code --> pre-processing --> compilation --> linking --> loading --> execution
Yes, ".c/.cpp" file are compiled only once. But header are parsed per inclusion.
Yes object is executed only once because corresponding object-file is linked and loaded only once.
First point :
dvcl compilation unit is in a static library. If the code is not used, the compiled object (.o) is not included in resulting executable. As such, static SampleNamespace::MyClass myClass; is never executed. It won't be the same if you were using a dynamic library or explicitely linking the .o file at link time.
Second point :
Use you or not libraries, a source file (.c) or (.cpp) is only compiled (and linked into the executable) once. That's the reason for having .h files that are included in other files and as such processed one time per including file
Third point :
The object is effectively instantiated once, since the .o file is linked only once
Related
I just feel weird about how does that work ?
That my first time that I've ever seen that , two c++ files located in the same directory "Test1.cpp,Test2.cpp"
Test1.cpp :
#include <iostream>
void magic();
int main(){
magic();
return 0;
}
Test2.cpp :
#include <iostream>
using namespace std;
void magic(){
cout << "That's not a magic , it's a logical thing.." << endl;
}
As I mentioned above , they are in the same directory , with prototype of 'magic' function.
Now my question is , how does magic work without any inclusion of Test2.cpp ?
Does C++ include it by default ? if that's true , then why do we need to include our classes ? why do we need header file while cpp file can does its purpose ?
In order to obtain an executable from a C++ source code two main phases are required:
compilation phase;
linking phase.
The first one searches only for the signature of the functions and check if the function call is compatible with the found declarations.
The second one searches the implementation of the function among the libraries or objects linked through the options specified through command line of the linker (some compilers can automatically run the linker adding some command line options).
So you need to understand the compiler and linker options in order to understand this process.
The main catch of headers file is simplifying writing of code.
Let's think about next example:
test2.cpp
#include <iostream>
using namespace std;
void my ()
{ magic(); } // here we don't know what magic() is and compiler will complain
void magic(){
cout << "That's not a magic , it's a logical thing.." << endl;
}
This code gives next error:
gaal#linux-t420:~/Downloads> g++ test2.cpp
test2.cpp: In function ‘void my()’:
test2.cpp:6:9: error: ‘magic’ was not declared in this scope
{ magic(); } // here we don't know what magic() is and compiler will complain
^
To avoid this error we need to place declaration of magic() function before definition of my(). So it is good idea to place ALL declarations in one place. Header file is a such place. If we don't use headers, we'll need to paste declaration of magic() function in any cpp-file where it will be used.
I'm currently learning java at my university and I'm trying to keep up with C++ while we cover new stuff. In java I have static member fields and methods that are independent of objects created. This is what I'm aiming to do in c++.
I have a static function in the Collision.h file.
The program will compile only when I define the static function in the header file.
//.h file
static void debug() //compiles and function is usable
{
std::cout << "DEBUG from the collision class called in main" << std::endl;
}
//.cpp file
// <nothing>
when I define the function in the .cpp file the program will not compile.
//.h file
static void debug(); //does not compile
//.cpp file
void debug() //I've tried with and without static keyword here.
{
std::cout << "DEBUG from the collision class called in main" << std::endl;
}
I'm at a loss as to why this latter situation doesn't work. Are .cpp files only used when an object is created?
Thanks for any help. :)
A free function is already independent from objects. In C++ static has a few different meanings. For free functions, static means that the function has internal linkage, meaning it is only visible in the current translation unit (cpp file + headers).
Since your function is declared in a header you don't want the static keyword, otherwise every file that includes it will need to implement it (they essentially get there own version of the function). You also shouldn't define it in the header - leave it as void debug();. Define it in a cpp file instead.
So I am working on my first multiple file, non-toy, c++ project. I have a class that represents a multi-spectral image and all the information that goes along with it.
My problem is how to design the part of the program that loads and object of this class with a file from disk!
I don't think I need a class for this. Would switching to a functional approach be better for the file loading. This way I can have just a source file (.cpp) that has functions I can call while passing in pointers to the relevant objects that will be updated by the file accessed by the function.
I don't think static functions are what I want to use? As I understand it they(static functions) are for accessing static variables within a class, aren't they?
If I go the functional route, from main(), how do I access these functions? I assume I would include the functions .cpp file at the beginning of the main() containing file. From there how do I call the functions. Do i just use the function name or do I have to pre-pend something similar to what you have to pre-pend when including a class and then calling its methods.
Here is some example code of what I have tried and the errors I get.
OpenMultiSpec.cpp
#include <iostream>
void test(){
std::cout << "Test function accessed successfully" << std::endl;
}
main.cpp
int main(){
test();
return 1;
}
The error says " 'test' was not declared in this scope "
OpenMultiSpec.h
void test();
main.cpp
#include "OpenMultiSpec.h"
int main(){
test();
return 1;
}
If they're in two separate files, and in your case, one being a header, use
#include "OpenMultiSpec.h"
If you decide to only use one file (as your comment says above), you won't need #include for your header file. Just place your function declaration anywhere before you call it.
#include <iostream>
void test() {
std::cout << "Test function accessed successfully" << std::endl;
}
int main() {
test();
return 1;
}
(i have edited my original question to make it more understandable)
here is the prototype for the problem ....
//Txn.h ---this has a static variable, usable by the pgms including it.
class Txn
{
public:
static int i;
static void incr_int();
};
Txn::i=0;
//Txn.cpp
void Txn::incr_int() {i++;}
->produce LibTxn.so
//class1.cpp -> one of the pgm using the static var from Txn.h
#include Txn.h
Txn::incr_int()
-> produce class1.o, with LibTxn.so.
// class2.cpp ->another pgm using the static var from Txn.h
#include Txn.h
cout<<"Txn::i;
-> produce class2.o, by including LibTxn.so
-> .produce class3 (an exe) by using class1.o,class2.o. Since, both class1 and 2 has the statement "Txn::i=0" from "Txn.h", multiple declaration issue happens.
-> .If I remove the statement "Txn::i=0" from Txn.h, then "undefined reference" error appears.
-> .At high lvl, this problem is a kind of having a session variable, which should be assessible from any func in a exe. Those func can be in any obj files used to form the exe. I am fine for any sol, even without static. But I can't change the creation of different .o files (which are using this session var) and combining the .o to produce the exe.
It is hard to figure out exactly what the problem is if you cannot provide the real code, or at least an example which has the same problem as the real code.
However, most likely the root cause of the problem is that you are not only declaring, but also defining your class's static variable in the header file that contains the class definition.
This means that all the translation units (i.e. .cpp files) which include that header will contain a definition for the static variable, and when merging all the corresponding object files, the linker will eventually complain about that symbol being defined multiple times.
If this is the case, what you should do is to take the initialization of the static variable out of the header file which contains your class's definition and put it in one (and only one) .cpp file.
I tried to recreate the problem as you described, but it compiled just fine on my computer, and it is difficult to go further without seeing your code.
In the code below, the header tells (declares) every .cpp file that includes it about Foo::x, but Foo::x lives in (is defined in) Foo.cpp (and Foo.o)
foo.h:
class Foo {
public:
static int x;
};
Foo.cpp:
#include "foo.h"
int Foo::x;
main.cpp:
#include <iostream>
#include "foo.h"
int main(int argc, char *argv[]) {
Foo::x = 42;
std::cout << "Foo::x is " << Foo::x;
}
Yes. it worked by defining the static variable in .cpp.
Special thanks to Andy Prowl and iWerner.
OK folks. I have fixed the error by moving the variable definition, but I do not understand why there is a problem.
Simplified Background: I have an object and I want to track all instances of that object in a list, so I simply created a List<> static member of the class. Below was a simple representation that allowed me to play with it. If I have the line marked as "this line" in the static library. I get a run time error. The object is defined in a header file and is the same header file in both places. If I move "this line" to the code in my final application and it works.... Why? I just don't understand why it is different.
#include "stdafx.h"
#include <list>
using namespace std;
class someobject
{
public:
someobject()
{
// do some stuff.
theStaticList.push_back(this);
}
void func()
{
printf("Made it!!\n");
}
static list<someobject*> theStaticList;
};
list<someobject*> someobject::theStaticList; //*** This line
someobject global;
int main()
{
someobject initial;
initial.func();
global.func();
list<someobject*>::iterator iter;
printf("\n\nLoop the Static List\n");
for (iter = someobject::theStaticList.begin(); iter != someobject::theStaticList.end (); iter++)
(*iter)->func();
return 0;
}
If you put that line in a header file, then include the header into two or more source files, you're defining the list object in each source file where the header gets included.
This violates the one definition rule, so the linker will quite rightly give you an error when you do it.
You want to define the object in one (and only one) source file. For a library, that should be some object file in the library, not the user's source file though (at least as a general rule).