I'm having some trouble using header files.
I would like to "refresh" a .h file, in order to update all the values of the constants in it which depend on an extern variable (defined in the main .cc file).
This is approximately the situation:
Header file (header.h)
extern int extern_value;
const int one = value;
const int two = value * 2;
const int three = value * 3;
Main program
#include "header.h"
int extern_value;
int main(){
extern_value = 10;
// Here is where I would like to refresh the header file.
// Here is where I would like to have my dependant constants
// (one, two and three) being updated.
return 0;
}
Please consider that this is an extreme approximation of the problem.
Do you guys have any idea about how to solve it?
Thanks in advance.
EDIT:
This is my actual problem:
I would like to have a header file which contains all the graphical constants that my project needs. They ALL depend on the size of the display. The first thing that the main program does is getting information about the display size; THEN, I would like the program to "export" this information on the header file, so it can calculate all the graphical constants relatively to the size of the display.
You can't do this. For a variety of reasons, but not least because your variables are const, and the expression you use to compute a value to be assigned to them is not continually re-evaluated.
What you want is to use functions:
extern int extern_value;
int one() { return extern_value; }
int two() { return extern_value * 2; }
int three() { return extern_value * 3; }
Other notes:
You probably shouldn't have an extern variable for this. Pass value to the function instead:
int one(const int value) { return value; }
int two(const int value) { return 2 * value; }
int three(const int value) { return 3 * value; }
int main() {
int value = 10;
std::cout << one(value) << " " << two(value) << "\n";
return 0;
}
You can't "refresh" a header file. The content of the file is what you typed, and this is included (effectively, pasted into) the source file when you use #include "my_header.h". You can update the value associated with non-const variables, but if you want to repeatedly evaluate an expression with different values, the best way is to turn that expression into a function as shown above, and call the function with different parameters.
You'll probably need to either move the function definitions from the header to a source file, or mark them as inline, otherwise you may be warned (or receive errors) about multiple definitions if you use the same header in multiple source files.
To address your actual problem, if you need to expose information through extern variables, you'll need to make them non-const, and have your main() function initialise them, or do so during static initialisation. There are a number of issues to be aware of when doing this, so it's much safer to provide functions that compute the geometry accordingly, and base those computations on one or two function arguments, or a small number of extern variables that are statically initialised to something safe, then set appropriately once the information becomes available. Further details can be obtained by searching for e.g. static initialisation or extern variables.
In this case, you may wish to consider creating a class to hold your geometry and perform the relevant computations. A pointer to an instance of this class can be created as an extern variable, and initialised on program initialisation (i.e. statically). You can then provide the derived "constants" as member functions which calculate their result based on a small number of encapsulated values, which can be set / updated if necessary. You can even make it such that these are const, if you're careful.
See, for instance the example below (live demo):
// ******** HEADER FILE ********
class Geometry {
public:
Geometry(const int rows, const int cols)
: rows_(rows), cols_(cols) {}
int rows() const { return rows_; }
int cols() const { return cols_; }
int pixels() const { return rows_ * cols_; }
// whatever other "constants" you need, defined as functions
// containing expressions based on rows_ and cols_.
private:
// Make copy constructor & assignment operator private to prevent copying
Geometry(const Geometry&);
Geometry& operator=(const Geometry&);
// The data from which everything else is calculated
const int rows_;
const int cols_;
};
extern const Geometry* the_geometry;
// ******** SOURCE FILE ********
#include <iostream>
int main() {
const int rows = 80; // or however you get the number of rows
const int columns = 25; // or however you get the number of columns
the_geometry = new Geometry(rows, columns);
std::cout << the_geometry->pixels() << "\n";
return 0;
}
const Geometry* the_geometry = nullptr;
Related
I am trying to build a window controller for SDL with its own pseudo-pixels. I had the code working using a single big and ugly translation unit, but am now trying to refactor the same code into multiple units and classes.
In this class, I am attempting to define the controller for the window, and I am having trouble understanding how to work with a nested structure inside a class.
The errors I am getting are on the line Pixel* pixels[][];. The compiler complains that "incomplete type is not allowed". The struct seems to be fully defined in the .cpp.
The second error is that "an array may not have elements of this type"; I understand that the second dimension of an array has to be of a defined size, but how do I define this size at compile-time while keeping my code flexible for windows of different sizes?
//PxWindow.h
#include <SDL.h>
class PxWindow {
struct Pixel {
static int PARENT_PIXEL_SIZE;
// Data members
int x, y;
Color color;
// Methods
int screenX();
int screenY();
SDL_Rect getPixelRect();
};
// Private Data Member declarations
private:
int PIXEL_SIZE;
int NUM_PIXELS_X;
int NUM_PIXELS_Y;
// Public Data Member declarations
public:
Pixel* pixels[][];
SDL_Rect rects[][];
public:
PxWindow(int,int,int);
int getPixelSize();
int getNumX();
int getNumY();
};
// PxWindow.cpp
#include "PxWindow.h"
/*
* Pixel Structure method definitions
*/
SDL_Rect PxWindow::Pixel::getPixelRect() {
return SDL_Rect{ screenX(), screenY(), PARENT_PIXEL_SIZE, PARENT_PIXEL_SIZE };
};
int PxWindow::Pixel::screenX() { return x * PARENT_PIXEL_SIZE; }
int PxWindow::Pixel::screenY() { return y * PARENT_PIXEL_SIZE; }
/*
* PxWindow Class method definitions
*/
PxWindow::PxWindow(int px_size, int num_x, int num_y) :
PIXEL_SIZE(px_size),
NUM_PIXELS_X(num_x),
NUM_PIXELS_Y(num_y) {
Pixel::PARENT_PIXEL_SIZE = PIXEL_SIZE;
};
int PxWindow::getPixelSize() {
return PIXEL_SIZE;
};
int PxWindow::getNumX() {
return NUM_PIXELS_X;
};
int PxWindow::getNumY() {
return NUM_PIXELS_Y;
};
For the first error:
You should check your includes. Most likely one is missing to complete your struct "Pixel". You seem to use SDL_Rect, but I can't see the include for SDL in your header file.
For your second error:
To make the array a little more dynamic you would have to create a new array (arrayTwo) of array.size() + 1 and copy all data from array to arrayTwo yourself.
You could also use a (or two nested vectors for 2d), but it depends on your performance needs.
First of all, let me say I have read similar threads on how to initialize a global variable or how to properly implement global constants. Nevertheless, these questions did not really help me with my concrete problem, as also haven't any other ressources I've consulted. The problem is the following.
I (have to) declare in a header file header.h a variable that must be constant and used by the main function in main.cpp as well as other functions defined in a another file functions.cpp (that are previously declared in header.h). The problem is this constant is a runtime constant, whose value is given by the user. How should I proceed?
I think my best shot was to do as follows. In header.h
// Header guard
namespace n
{
// Some forward declarations
extern const double mu; // The constant that should be initialized by the user.
// Some other declarations
}
then in functions.cpp
#include "header.h"
namespace n
{
// Some definitions here
double function_that_uses_mu(double a, double b)
{
// Some code using mu
return somedouble;
}
// Some other definitions
}
finally main.cpp
#include "header.h"
#include <iostream>
int main()
{
// Some code
double value_of_mu{};
std::cin >> value_of_mu;
// Validity check
extern const double n::mu{ value_of_mu };
// More code
return 0;
}
The problem is that compilation fails due to the fact that error: ‘mu’ has both ‘extern’ and initializer. However, if I tried mu = value_of_mu I would obviously get an error because I would be assigning to a const value (not initialising it). So I don't know how to proceed, or what's wrong with my code. There are two mandatory facts I must respect:
Functions/global-consts definitions, functions/global-consts declarations and main must be split in the three aforementioned files.
mu is to be defined as a constant shared by all three files.
Is this possible? How?
EDIT:
I think my problem is that an exten variable can't be initialised inside a function, but if this is so, I don't see how I do what I'm trying to.
Think about it: If a value needs to be set during the lifetime of a program, it's not really a constant. So, you shouldn't try to pretend it's a constant by declaring it as const. If you don't want the program to accidentally change its value, you have to protect it in some other way, such as making it a private member variable of a class. That way, you can restrict access to only return the value of mu as a const.
// muholder.h
class muholder
{
private:
double m_value;
public:
muholder (double ivalue): m_value(ivalue) {}
double const &value() const { return m_value; }
};
// workflow_envelope.h
class workflow_envelope
{
private:
muholder m_mu;
public:
workflow_envelope (double imu): m_mu(imu) {}
bool validity_check();
double method_that_uses_mu (double a, double b) const { return a*m_mu.value()/ b; }
void run(); // any "more code" goes in here.
};
// main
#include "workflow_envelope.h"
#include <iostream>
int main()
{
// Some code
double value_of_mu;
if (std::cin >> value_of_mu)
{
// Validity check
workflow_envelope workflow(value_of_mu);
if (workflow.validity_check())
{
workflow.run();
return 0;
}
}
return 1;
}
When you initialize a variable, you can't specify extern. This should work instead:
int main()
{
// Some code
double value_of_mu{};
std::cin >> value_of_mu;
// Validity check
using namespace n;
const double mu = value_of_mu; // no extern specifier
// More code
return 0;
}
This is my first question:
I am trying to read "global attributes" from a NetCDF file (using the C++ legacy API). By "global attribute" I mean an attribute that was added to a NcFile, not to a NcVar.
For most things the "Example netCDF programs" are useful -- but there is no example for "global attributes".
Consulting the "netcdfcpp.h" I find a few things:
NcFile has a member function: NcAtt* get_att(NcToken) const;
NcAtt has NO public constructor
NcAtt is friends with NcFile: friend class NcFile;
NcAtt has a private constructor: NcAtt( NcFile*, NcToken);
NcAtt has a public member function NcValues* values( void ) const;
NcValues has an API defined through the ncvalues.h header
My coding skills are insufficient to understand how I get back at the string/int/float stored as NcValue, in an NcAtt class within NcFile.
Attached is a example code of my problem "NetCDF_test.cpp", with the critical part missing from the implementation of the "LoadNetCDF" function.
The code compiles OK with: (edit: also, "TestFile.nc" is created correctly)
g++ -c NetCDF_test.cpp -o NetCDF_test.o
g++ -o NCTEST NetCDF_test.o -lnetcdf_c++ -lnetcdf
Example code:
#include <iostream> // provides screen output (i.e. std::cout<<)
#include <netcdfcpp.h>
struct MyStructure {
std::string MyString;
int MyInt;
float MyFloat;
MyStructure(); // default constructor
int SaveNetCDF(std::string); // Save the struct content to "global attributes" in NetCDF
int LoadNetCDF(std::string); // Load the struct content from "global attributes" in NetCDF
};
MyStructure::MyStructure(void)
{
MyString = "TestString";
MyInt = 123;
MyFloat = 1.23;
}
int MyStructure::SaveNetCDF(std::string OUTPUT_FILENAME)
{
NcError err(NcError::silent_nonfatal);
static const int NC_ERR = 2;
NcFile NetCDF_File(OUTPUT_FILENAME.c_str(), NcFile::Replace);
if(!NetCDF_File.is_valid()) {return NC_ERR;}
if(!(NetCDF_File.add_att("MyString",MyString.c_str()))) {return NC_ERR;}
if(!(NetCDF_File.add_att("MyInt",MyInt))) {return NC_ERR;}
if(!(NetCDF_File.add_att("MyFloat",MyFloat))) {return NC_ERR;}
return 0;
}
int MyStructure::LoadNetCDF(std::string INPUT_FILENAME)
{
NcError err(NcError::silent_nonfatal);
static const int NC_ERR = 2;
NcFile NetCDF_File(INPUT_FILENAME.c_str(), NcFile::ReadOnly);
if(!NetCDF_File.is_valid()) {return NC_ERR;}
// ???? This is where I am stuck.
// How do I read the global attribute from the NetCDF_File ??
return 0;
}
int main()
{
std::cout<< "START OF TEST.\n";
MyStructure StructureInstance; // datamembers initialized by constructor
StructureInstance.SaveNetCDF("TestFile.nc");
StructureInstance.MyString = "Change string for sake of testing";
StructureInstance.MyInt = -987;
StructureInstance.MyFloat = -9.87;
StructureInstance.LoadNetCDF("TestFile.nc"); // data members are supposed to be read from file
std::cout<< "Now the data members of StructureInstance should be TestString, 123, and 1.23\n";
std::cout<< StructureInstance.MyString << " ; " << StructureInstance.MyInt << " ; " << StructureInstance.MyFloat <<"\n";
std::cout<< "END OF TEST.\n";
}
It's pretty clearly spelled out in the C++ users guide: http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-cxx/Class-NcAtt.html#Class-NcAtt
"Because attributes are only associated with open netCDF files, there are no public constructors for this class. Use member functions of NcFile and NcVar to get netCDF attributes or add new attributes."
global attributes are attributes on the file (as opposed to variable attributes which are, well, attributes on the variable)
NetCDF_File.num_atts() returns how many global attributes. The get_att() methods (overloaded in various ways) will get you an attribute.
consult http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-cxx/Class-NcFile.html#Class-NcFile
Many thanks to Rob Latham for the links to a commented description of the NetCDF API (legacy C++). With the information given there I was able to figure it out:
NcAtt inherents form NcTypedComponent a set of member functions for accessing data stored within a given NcAtt: (int n == n-th element)
ncbyte as_ncbyte( int n ) const
char as_char( int n ) const
short as_short( int n ) const
int as_int( int n ) const
nclong as_nclong( int n ) const // deprecated
long as_long( int n ) const
float as_float( int n ) const
double as_double( int n ) const
char* as_string( int n ) const
But still, the constructor for NcAtt is private and the only access point to an existing NcAtt is through the NcFile member function NcVar* get_var(NcToken name) const -- which only returns a pointer. Hence the straight forward usage does not work:
int MyInt = MyNcFile.get_att("MyInt").as_int(0); // DOES NOT COMPILE
However, dereferencing the pointer returned by get_att does the trick.
int MyInt = (*MyNcFile.get_att("MyInt")).as_int(0); // WORKS
For sake of completeness I include below the implementation of MyStructure::LoadNetCDF for the example code of my original question.
int MyStructure::LoadNetCDF(std::string INPUT_FILENAME)
{
NcError err(NcError::silent_nonfatal);
static const int NC_ERR = 2;
NcFile NetCDF_File(INPUT_FILENAME.c_str(), NcFile::ReadOnly);
if(!NetCDF_File.is_valid()) {return NC_ERR;}
// NcAtt constructor is private, but one can obtain the pointer to an existing NcAtt
NcAtt* PointerToMyIntNcAtt = NetCDF_File.get_att("MyInt");
// Now, using the dereferencing operator one has access to the member functions that NcAtt inherents from NcTypedComponent
if(!(*PointerToMyIntNcAtt).is_valid()) {return NC_ERR;}
std::cout<< "Is MyInt a valid NcAtt? "<< (*PointerToMyIntNcAtt).is_valid()<<"\n";
// The concise way of writing the access to NetCDF "global attributes"" of type int/float/string
MyInt = (*NetCDF_File.get_att("MyInt")).as_int(0);
MyFloat = (*NetCDF_File.get_att("MyFloat")).as_float(0);
MyString = (*NetCDF_File.get_att("MyString")).as_string(0);
return 0;
}
I'm trying to implement a minheap in C++. However the following code keeps eliciting errors such as :
heap.cpp:24:4: error: cannot convert 'complex int' to 'int' in assignment
l=2i;
^
heap.cpp:25:4: error: cannot convert 'complex int' to 'int' in assignment
r=2i+1;
^
heap.cpp: In member function 'int Heap::main()':
heap.cpp:47:16: error: no matching function for call to 'Heap::heapify(int [11], int&)'
heapify(a,i);
^
heap.cpp:47:16: note: candidate is:
heap.cpp:21:5: note: int Heap::heapify(int)
int heapify(int i) //i is the parent index, a[] is the heap array
^
heap.cpp:21:5: note: candidate expects 1 argument, 2 provided
make: * [heap] Error 1
#include <iostream>
using namespace std;
#define HEAPSIZE 10
class Heap
{
int a[HEAPSIZE+1];
Heap()
{
for (j=1;j<(HEAPISZE+1);j++)
{
cin>>a[j];
cout<<"\n";
}
}
int heapify(int i) //i is the parent index, a[] is the heap array
{
int l,r,smallest,temp;
l=2i;
r=2i+1;
if (l<11 && a[l]<a[i])
smallest=l;
else
smallest=i;
if (r<11 && a[r]<a[smallest])
smallest=r;
if (smallest != i)
{
temp = a[smallest];
a[smallest] = a[i];
a[i]=temp;
heapify(smallest);
}
}
int main()
{
int i;
for (i=1;i<=HEAPSIZE;i++)
{
heapify(a,i);
}
}
}
Ultimately, the problem with this code is that it was written by someone who skipped chapters 1, 2 and 3 of "C++ for Beginners". Lets start with some basics.
#include <iostream>
using namespace std;
#define HEAPSIZE 10
Here, we have included the C++ header for I/O (input output). A fine start. Then, we have issued a directive that says "Put everything that is in namespace std into the global namespace". This saves you some typing, but means that all of the thousands of things that were carefully compartmentalized into std:: can now conflict with names you want to use in your code. This is A Bad Thing(TM). Try to avoid doing it.
Then we went ahead and used a C-ism, a #define. There are times when you'll still need to do this in C++, but it's better to avoid it. We'll come back to this.
The next problem, at least in the code you posted, is a misunderstanding of the C++ class.
The 'C' language that C++ is based on has the concept of a struct for describing a collection of data items.
struct
{
int id;
char name[64];
double wage;
};
It's important to notice the syntax - the trailing ';'. This is because you can describe a struct and declare variables of it's type at the same time.
struct { int id; char name[64]; } earner, manager, ceo;
This declares a struct, which has no type name, and variables earner, manager and ceo of that type. The semicolon tells the compiler when we're done with this statement. Learning when you need a semicolon after a '}' takes a little while; usually you don't, but in struct/class definition you do.
C++ added lots of things to C, but one common misunderstanding is that struct and class are somehow radically different.
C++ originally extended the struct concept by allowing you to describe functions in the context of the struct and by allowing you to describe members/functions as private, protected or public, and allowing inheritance.
When you declare a struct, it defaults to public. A class is nothing more than a struct which starts out `private.
struct
{
int id;
char name[64];
double wage;
};
class
{
public:
int id;
char name[64];
double wage;
};
The resulting definitions are both identical.
Your code does not have an access specifier, so everything in your Heap class is private. The first and most problematic issue this causes is: Nobody can call ANY of your functions, because they are private, they can only be called from other class members. That includes the constructor.
class Foo { Foo () {} };
int main()
{
Foo f;
return 0;
}
The above code will fail to compile, because main is not a member of Foo and thus cannot call anything private.
This brings us to another problem. In your code, as posted, main is a member of Foo. The entry point of a C++ program is main, not Foo::main or std::main or Foo::bar::herp::main. Just, good old int main(int argc, const char* argv[]) or int main().
In C, with structs, because C doesn't have member functions, you would never be in a case where you were using struct-members directly without prefixing that with a pointer or member reference, e.g. foo.id or ptr->wage. In C++, in a member function, member variables can be referenced just like local function variables or parameters. This can lead to some confusion:
class Foo
{
int a, b;
public:
void Set(int a, int b)
{
a = a; // Erh,
b = b; // wat???
}
};
There are many ways to work around this, but one of the most common is to prefix member variables with m_.
Your code runs afoul of this, apparently the original in C passed the array to heapify, and the array was in a local variable a. When you made a into a member, leaving the variable name exactly the same allowed you not to miss the fact that you no-longer need to pass it to the object (and indeed, your heapify member function no-longer takes an array as a pointer, leading to one of your compile errors).
The next problem we encounter, not directly part of your problem yet, is your function Heap(). Firstly, it is private - you used class and haven't said public yet. But secondly, you have missed the significance of this function.
In C++ every struct/class has an implied function of the same name as the definition. For class Heap that would be Heap(). This is the 'default constructor'. This is the function that will be executed any time someone creates an instance of Heap without any parameters.
That means it's going to be invoked when the compiler creates a short-term temporary Heap, or when you create a vector of Heap()s and allocate a new temporary.
These functions have one purpose: To prepare the storage the object occupies for usage. You should try and avoid as much other work as possible until later. Using std::cin to populate members in a constructor is one of the most awful things you can do.
We now have a basis to begin to write the outer-shell of the code in a fashion that will work.
The last change is the replacement of "HEAPSIZE" with a class enum. This is part of encapsulation. You could leave HEAPSIZE as a #define but you should expose it within your class so that external code doesn't have to rely on it but can instead say things like Heap::Size or heapInstance.size() etc.
#include <iostream>
#include <cstdint> // for size_t etc
#include <array> // C++11 encapsulation for arrays.
struct Heap // Because we want to start 'public' not 'private'.
{
enum { Size = 10 };
private:
std::array<int, Size> m_array; // meaningful names ftw.
public:
Heap() // default constructor, do as little as possible.
: m_array() // says 'call m_array()s default ctor'
{}
// Function to load values from an istream into this heap.
void read(std::istream& in)
{
for (size_t i = 0; i < Size; ++i)
{
in >> m_array[i];
}
return in;
}
void write(std::ostream& out)
{
for (size_t i = 0; i < Size; ++i)
{
if (i > 0)
out << ','; // separator
out << m_array[i];
}
}
int heapify(size_t index)
{
// implement your code here.
}
}; // <-- important.
int main(int argc, const char* argv[])
{
Heap myHeap; // << constructed but not populated.
myHeap.load(std::cin); // read from cin
for (size_t i = 1; i < myHeap.Size; ++i)
{
myHeap.heapify(i);
}
myHead.write(std::cout);
return 0;
}
Lastly, we run into a simple, fundamental problem with your code. C++ does not have implicit multiplication. 2i is the number 2 with a suffix. It is not the same as 2 * i.
int l = 2 * i;
There is also a peculiarity with your code that suggests you are mixing between 0-based and 1-based implementation. Pick one and stick with it.
--- EDIT ---
Technically, this:
myHeap.load(std::cin); // read from cin
for (size_t i = 1; i < myHeap.Size; ++i)
{
myHeap.heapify(i);
}
is poor encapsulation. I wrote it this way to draw on the original code layout, but I want to point out that one reason for separating construction and initialization is that it allows initialization to be assured that everything is ready to go.
So, it would be more correct to move the heapify calls into the load function. After all, what better time to heapify than as we add new values, keeping the list in order the entire time.
for (size_t i = 0; i < Size; ++i)
{
in >> m_array[i];
heapify(i);
}
Now you've simplified your classes api, and users don't have to be aware of the internal machinery.
Heap myHeap;
myHeap.load(std::cin);
myHeap.write(std::cout);
I'm considering a certain solution where I would like to initialize a cell of an array that is defined in other module (there will be many modules initializing one table). The array won't be read before running main (so there is not problem with static initialization order).
My approach:
/* secondary module */
extern int i[10]; // the array
const struct Initialize {
Initialize() { i[0] = 12345; }
} init;
/* main module */
#include <stdio.h>
int i[10];
int main()
{
printf("%d\n", i[0]); // check if the value is initialized
}
Compiler won't strip out init constant because constructor has side effects. Am I right? Is the mechanism OK? On GCC (-O3) everything is fine.
//EDIT
In a real world there will be many modules. I want to avoid an extra module, a central place that will gathered all minor initialization routines (for better scalability). So this is important that each module triggers its own initialization.
This works with MSVC compilers but with GNU C++ does not (at least for me). GNU linker will strip all the symbol not used outside your compilation unit. I know only one way to guarantee such initialization - "init once" idiom. For examle:
init_once.h:
template <typename T>
class InitOnce
{
T *instance;
static unsigned refs;
public:
InitOnce() {
if (!refs++) {
instance = new T();
}
}
~InitOnce() {
if (!--refs) {
delete instance;
}
}
};
template <typename T> unsigned InitOnce<T>::refs(0);
unit.h:
#include "init_once.h"
class Init : public InitOnce<Init>
{
public:
Init();
~Init();
};
static Init module_init_;
secondary.cpp:
#include "unit.h"
extern int i[10]; // the array
Init::Init()
{
i[0] = 12345;
}
...
I don't think you want the extern int i[10]; in your main module, though, adf88.
EDIT
/*secondary module (secondary.cpp) */
int i[10];
void func()
{
i[0]=1;
}
.
/*main module (main.cpp)*/
#include<iostream>
extern int i[];
void func();
int main()
{
func();
std::cout<<i[0]; //prints 1
}
Compile, link and create and executable using g++ secondary.cpp main.cpp -o myfile
In general constructors are used(and should be used) for initializing members of a class only.
This might work, but it's dangerous. Globals/statics construction order within a single module is undefined, and so is module loading order (unless you're managing it explicitly). For example, you assume that during secondary.c Initialize() ctor run, i is already present. You'd have to be very careful not to have two modules initialize the same common data, or have two modules carry out initializations with overlapping side effects.
I think a cleaner design to tackle such a need is to have the owner of the common data (your main module) expose it as a global singleton, with an interface to carry out whichever data initializations needed. You'd have a central place to control init-order, and maybe even control concurrent access (using critical sections or other concurrency primitives). Along the lines of your simplified example, that might be -
/main module (main.c)/
#include
class CommonDat
{
int i;
public:
const int GetI() { return i;}
void SetI(int newI) { i = newI; }
void incI()
{
AcquireSomeLock();
i++;
ReleaseTheLock();
}
}
CommonDat g_CommonDat;
CommonDat* getCommonDat() { return &g_CommonDat; }
int main(void)
{
printf("%d",getCommonDat()->GetI());
}
It's also preferable to have the secondary modules call these interfaces at controlled times in runtime (and not during the global c'tors pass).
(NOTE: you named the files as C files, but tagged the question as c++. The suggested code is c++, of course).
May I ask why you use an array (running the risk of getting out of bounds) when you could use a std::vector ?
std::vector<int>& globalArray()
{
static std::vector<int> V;
return V;
}
bool const push_back(std::vector<int>& vec, int v)
{
vec.push_back(v);
return true; // dummy return for static init
}
This array is lazily initialized on the first call to the function.
You can use it like such:
// module1.cpp
static bool const dummy = push_back(globalArray(), 1);
// module2.cpp
static bool const dummy = push_back(globalArray(), 2);
It seems much easier and less error-prone. It's not multithread compliant until C++0x though.