Re: When is the non-local static variable constructor run?
Am 26.01.2012 20:49, schrieb paul_71:
[..]
Yes, this is a commonly used idiom of "registrars" for e.g.
deserialization object factories... Unfortunately it is very easy to
break on every implementation I have tried. If such non-locals as the
"sc" from your example live in "static libraries" then the applied
linker optimization strategies are not able to see the side effects of
"sc" constructors. In your example, whenever a linker sees a usage of
"sc" (as in sc.SomeFunction()) the constructor for sc will be run. If
it does not, the symbol "sc" is just removed and the program behaves
as it would not be present.
As explained in my reply, this is easy to fix for static libraries in
practice. Just define a static variable in every *header* of the library
where the constructor calls a single time a function local static
variable. Here a sketch:
// register_api.h: (Needed for registration)
namespace api {
template<class T>
class RegistryProxy;
namespace details {
class Registry
{
template<class>
friend class api::RegistryProxy;
Registry(const char* id);
};
} // details
template<class T>
class RegistryProxy
{
static details::Registry& init(const char* id) {
static details::Registry result(id);
return result;
}
public:
RegistryProxy(const char* id) { init(id); }
};
}
// query_api.h: (needed to check the registry contents)
#include <vector>
#include <string>
namespace api {
typedef std::vector<std::string> ContType;
ContType allIds();
}
// register_lib.cpp
#include "register_api.h"
#include "query_api.h"
namespace api {
namespace details {
namespace {
inline ContType& ids()
{
static ContType result;
return result;
}
} // anon
Registry::Registry(const char* id)
{
ids().push_back(id);
}
} // details
ContType allIds()
{
return details::ids();
}
} // api
Now lets consider a static library user_api, which provides an api header:
//user_api.h:
#include "user_api_register.h"
namespace user_api {
// Something to export
}
// user_api_register.h (internally needed to ensure proper registration)
#include "register_api.h"
namespace user_api {
namespace details {
class UserType;
namespace {
api::RegistryProxy<UserType> force_registration_do_not_use("user_api");
}
}
}
Finally we have a test program that depends on the static user library
and does show the registry contents:
#include <iostream>
#include <algorithm>
#include <iterator>
#include "query_api.h"
#include "user_api.h" // This could have been included by any other
// TU of the main program. For simplicity it
// is included here.
int main()
{
api::ContType ids = api::allIds();
std::copy(ids.begin(), ids.end(),
std::ostream_iterator<std::string>(std::cout, "\n"));
}
Greetings from Bremen,
Daniel Kr?gler
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]