U
user
Hi.
Sorry for the probable dumbness of my question, but the behaviour I'm
observing seems a blatant defect in the C++ Standard or in the
implementation I'm using (several different versions of GCC, all
behaving exactly the same, GNU binutils, GNU/Linux on PowerPC).
Let's say I have two compilation units, a.cc and b.cc; each of them
need to perform some initialization (or finalization, for what it
matters) which I want to be transparent, i.e. not visible outside the
module. A solution is defining in each of a.cc and b.cc an Initializer
class with a constructor (or destructor in the case of finalization);
for each initializer class there will be one and only one static
instance, in the respective compilation unit.
Note that each instance of the initializer classes cannot see the
other instance, nor the other class. Let's say I don't care about the
order in which the two initializations are performed.
The issue is that if I happen to give the same name to both
'initializer' classes, I see that the constructor of *one* class is
executed twice. Using different names or different namespaces for
initializer classes solves the probem, but I feel the situation is
however ugly, because a user unaware of the initializer class in some
compilation unit can make a mess. The implementation 'escapes' the
interface border, which is bad.
I don't know what the Standard has to say about this matter; however
even if the Standard dictated the semantics that we would expect I doubt
that the problem could be solved, even at the compiler level with a
different mangling which included the compilation unit name: for example
there could be several files with the same name in different
directories; and a single directory can have multiple name in any
filesystem supporting symlinks.
The linker calls the constructor defined in the *first* compilation
unit found in the command line:
[luca@ibook /tmp]$ g++ -Wall a.cc b.cc && ./a.out
Initialization performed (1)
Initialization performed (1)
Executed code from b.cc
[luca@ibook /tmp]$ g++ -Wall b.cc a.cc && ./a.out
Initialization performed (2)
Initialization performed (2)
Executed code from b.cc
Here is the distilled code:
/* ------------------------------- a.cc --------------------------- */
#include <iostream>
class Initializer{
public:
Initializer(){
std::cerr << "Initialization performed (1)\n";
}
}; // class
static Initializer theInitializer1;
void fromB(); // declaration of something in b.cc
int main(){
fromB();
return 0;
}
/* ------------------------------- a.cc (end)---------------------- */
/* ------------------------------- b.cc --------------------------- */
#include <iostream>
void fromB(){
std::cerr << "Executed code from b.cc\n";
}
class Initializer{
public:
Initializer(){
std::cerr << "Initialization performed (2)\n";
} // class
};
/* The constructor in a.cc is called!!! */
static Initializer theInitializer2;
/* ------------------------------- b.cc (end) --------------------- */
Does a reasonable solution exist in C++?
From an 'academic' point of view, how could it be implemented, even
if not allowed by the C++ Standard?
Thanks in advance,
Sorry for the probable dumbness of my question, but the behaviour I'm
observing seems a blatant defect in the C++ Standard or in the
implementation I'm using (several different versions of GCC, all
behaving exactly the same, GNU binutils, GNU/Linux on PowerPC).
Let's say I have two compilation units, a.cc and b.cc; each of them
need to perform some initialization (or finalization, for what it
matters) which I want to be transparent, i.e. not visible outside the
module. A solution is defining in each of a.cc and b.cc an Initializer
class with a constructor (or destructor in the case of finalization);
for each initializer class there will be one and only one static
instance, in the respective compilation unit.
Note that each instance of the initializer classes cannot see the
other instance, nor the other class. Let's say I don't care about the
order in which the two initializations are performed.
The issue is that if I happen to give the same name to both
'initializer' classes, I see that the constructor of *one* class is
executed twice. Using different names or different namespaces for
initializer classes solves the probem, but I feel the situation is
however ugly, because a user unaware of the initializer class in some
compilation unit can make a mess. The implementation 'escapes' the
interface border, which is bad.
I don't know what the Standard has to say about this matter; however
even if the Standard dictated the semantics that we would expect I doubt
that the problem could be solved, even at the compiler level with a
different mangling which included the compilation unit name: for example
there could be several files with the same name in different
directories; and a single directory can have multiple name in any
filesystem supporting symlinks.
The linker calls the constructor defined in the *first* compilation
unit found in the command line:
[luca@ibook /tmp]$ g++ -Wall a.cc b.cc && ./a.out
Initialization performed (1)
Initialization performed (1)
Executed code from b.cc
[luca@ibook /tmp]$ g++ -Wall b.cc a.cc && ./a.out
Initialization performed (2)
Initialization performed (2)
Executed code from b.cc
Here is the distilled code:
/* ------------------------------- a.cc --------------------------- */
#include <iostream>
class Initializer{
public:
Initializer(){
std::cerr << "Initialization performed (1)\n";
}
}; // class
static Initializer theInitializer1;
void fromB(); // declaration of something in b.cc
int main(){
fromB();
return 0;
}
/* ------------------------------- a.cc (end)---------------------- */
/* ------------------------------- b.cc --------------------------- */
#include <iostream>
void fromB(){
std::cerr << "Executed code from b.cc\n";
}
class Initializer{
public:
Initializer(){
std::cerr << "Initialization performed (2)\n";
} // class
};
/* The constructor in a.cc is called!!! */
static Initializer theInitializer2;
/* ------------------------------- b.cc (end) --------------------- */
Does a reasonable solution exist in C++?
From an 'academic' point of view, how could it be implemented, even
if not allowed by the C++ Standard?
Thanks in advance,