469,331 Members | 1,817 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,331 developers. It's quick & easy.

Static initialization dependency -- Think in C++ 2nd

I will present very long code, hope someone will read it all, and teach me
something like tom_usenet.

This question comes to me when i read <<Think in C++>> 2nd, chapter 10 ,
name control, section "Static initialization dependency". There is a
example to show how to solve the prolem involved with a technique first
poineered by Jerry Schwarz while creating the iostream library (because the
definitions for cin, cout, and cerr are static and live in a separate file).

The idea is to use a additional class responsible for the dynamic
initialization of your library¡¯s static objects.

Here in the code following, the static objects is std::ofstream out,
intended to be used as a log file maybe, and the addition class is
Initializer. In class Initializer's constructor, out initialize the log
file... but code stop there with a access voilation exception.......

I'm eager to know why....

----------------------------------------------------------------------------
----
//: C10:Initializer.h
// Static initialization technique
#ifndef INITIALIZER_H
#define INITIALIZER_H
#include <iostream>
#include <fstream>
extern std::ofstream out;

class Initializer {
static int initCount;
public:
Initializer();
~Initializer();
};
// The following creates one object in each
// file where Initializer.h is included, but that
// object is only visible within that file:
static Initializer init;
#endif // INITIALIZER_H ///:~
-----------------------------------------------------------------------

//Initializer.cpp
#include "Initializer.h"
#include <fstream>
#include <iostream>
Initializer::Initializer(){
// Initialize first time only
if(initCount++ == 0) {
std::cout << out.is_open() << std::endl; //return 0
// to test if out is good to work with
///////////////////////////////////////////////////////////////////
out.open("hello.txt"); // program stuck here......
///////////////////////////////////////////////////////////////////
// debug give infomation like this :
//First-chance exception in test.exe: 0xC0000005: Access Violation.
// i use VC++ 6.0.
}
}
Initializer::~Initializer()
{
std::cout << "~Initializer()" << std::endl;
// Clean up last time only
if(--initCount == 0) {
out.close();
// Any necessary cleanup here
}
}
------------------------------------------------------------------------
//: C10:InitializerDefs.cpp {O}
// Definitions for Initializer.h
#include "Initializer.h"
#include <fstream>
// Static initialization will force
// all these values to zero:
std::ofstream out;
int Initializer::initCount;
///:~
------------------------------------------------------------------------
// test file......
//: C10:Initializer2.cpp
//{L} InitializerDefs Initializer
// Static initialization
#include "Initializer.h"
using namespace std;

int main() {
out << "hello" << endl;
return 0;
} ///:~
------------------------------------------------------------------------
Jul 22 '05 #1
1 4361
Tom
"Qin Chen" <wi*******@etang.com> wrote in message news:<c1*************@ID-226321.news.uni-berlin.de>...
I will present very long code, hope someone will read it all, and teach me
something like tom_usenet.

This question comes to me when i read <<Think in C++>> 2nd, chapter 10 ,
name control, section "Static initialization dependency". There is a
example to show how to solve the prolem involved with a technique first
poineered by Jerry Schwarz while creating the iostream library (because the
definitions for cin, cout, and cerr are static and live in a separate file).
I just downloaded the book and had a look, and unfortunately the
solution he proposes only works for POD objects. For non-PODs, the
details are somewhat different, and worse, there is no completely
portable way to do it.

The idea is to use a additional class responsible for the dynamic
initialization of your library¡¯s static objects.
Right, however, you need to use some platform specific trickery to
initialize the ostream. Read on...

Here in the code following, the static objects is std::ofstream out,
intended to be used as a log file maybe, and the addition class is
Initializer. In class Initializer's constructor, out initialize the log
file... but code stop there with a access voilation exception.......

I'm eager to know why....
It's because "out" hasn't been constructed by the time your
Initializer object attempts to access it (calling "open"). The order
that global objects from different translation units are initialized
in is not well defined - this is the infamous "static initialization
dependency fiasco". There are a number of ways of solving it, all of
which depend on some level of platform specific behaviour or compiler
extensions. I'll present a mostly portable version.

Incidently, one non-portable solution, for MSVC, is:
Add the following to InitializerDefs.cpp, just before the "out"
definition:
#pragma init_seg(compiler)

That forces the compiler to initialize objects declared in that
segment before initializing normal globals. Read on for a more
portable solution.

----------------------------------------------------------------------------
----
//: C10:Initializer.h
// Static initialization technique
#ifndef INITIALIZER_H
#define INITIALIZER_H
#include <iostream>
#include <fstream>
For my "portable" solution you need
extern std::ofstream* const out_pointer;
static std::ofstream& out = *out_pointer; //dynamic initialization

class Initializer {
static int initCount;
public:
Initializer();
~Initializer();
};
// The following creates one object in each
// file where Initializer.h is included, but that
// object is only visible within that file:
static Initializer init;
#endif // INITIALIZER_H ///:~
-----------------------------------------------------------------------

//Initializer.cpp
#include "Initializer.h"
#include <fstream>
#include <iostream>
Initializer::Initializer(){
// Initialize first time only
if(initCount++ == 0) {
std::cout << out.is_open() << std::endl; //return 0
// to test if out is good to work with
///////////////////////////////////////////////////////////////////
Here you should construct the stream in the storage that the reference
points to:
new (out_pointer) std::ofstream("hello.txt");
out.open("hello.txt"); // program stuck here......
Now you don't need that.
///////////////////////////////////////////////////////////////////
// debug give infomation like this :
//First-chance exception in test.exe: 0xC0000005: Access Violation.
// i use VC++ 6.0.
}
}
Initializer::~Initializer()
{
std::cout << "~Initializer()" << std::endl;
// Clean up last time only
if(--initCount == 0) {
out.close();
Here you need to destroy the stream:
typedef std::ofstream ofs;
out_pointer->~ofs();
// Any necessary cleanup here
}
}
------------------------------------------------------------------------
//: C10:InitializerDefs.cpp {O}
// Definitions for Initializer.h
#include "Initializer.h"
#include <fstream>
// Static initialization will force
// all these values to zero:
std::ofstream out;
Here's where you do the "portable" hack:

#include <cstddef>

namespace
{

union aligner
{
long double v1;
double v2;
long v3;
void (*v4)();
class dummy;
void (dummy::*v5);
void (dummy::*v6)();
void* v7;
};

std::size_t const temp_aligner_count = sizeof(std::ofstream) /
sizeof(aligner);
std::size_t const aligner_count = sizeof(std::ofstream) %
sizeof(aligner) ?
temp_aligner_count + 1 : temp_aligner_count;

//this is enough storage to fit the stream in:
aligner out_storage[aligner_count]; //hope this is properly aligned!

} //close anon namespace

//here's more "trickery". This is static initialization, hence carried
out
//before program start (and before init's etc. get initialized.
std::ofstream* const out_pointer =
reinterpret_cast<std::ofstream*>(out_storage);

int Initializer::initCount;
///:~
------------------------------------------------------------------------
// test file......
//: C10:Initializer2.cpp
//{L} InitializerDefs Initializer
// Static initialization
#include "Initializer.h"
using namespace std;

int main() {
out << "hello" << endl;
return 0;
} ///:~


With those changes, the above should work fine.

Tom
Jul 22 '05 #2

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

49 posts views Thread by bearophileHUGS | last post: by
12 posts views Thread by chandu | last post: by
14 posts views Thread by Jeroen | last post: by
10 posts views Thread by n.torrey.pines | last post: by
20 posts views Thread by JohnQ | last post: by
6 posts views Thread by gs | last post: by
1 post views Thread by CARIGAR | last post: by
reply views Thread by Purva khokhar | last post: by
1 post views Thread by haryvincent176 | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.