Question about a static vector<*A> in class A

J

Jojo

I have a code like (just some illustrative lines, many things are omitted):

class string_interpreter {
static std::vector<* string_interpreter> my_vector;
*string_interpreter init(const string& s);
... // There's an "operator =" also, and ctor, dtor.
};

*string_interpreter string_interpreter::init(const string& s)
{
// Look in the vector if string 's' was already interpreted.

for (int i = 0; i < vector.length(); ++i)
if (//string 's' is already interpreted)
return vector; // return the result of the interpretation

// Not in the vector, do string interpretation. Store results in the
// class's properties.

...

// Save results in the vector and return.

string_interpreter *new_interpreted_string = new string_interpreter;
*new_interpreted_string = *this;
my_vector.push_back(new_interpreted_string);
return new_interpreted_string;
}

So, basically this class accepts a string, interprets it and stores the
results in its own properties. Then the class makes sure that every
interpreted string (and its results, all within the class itself) is
stored in a vector to ensure that a string needs be interpreted only once.

The reason why I store pointers in the vector and not the objects
itself, is that these pointers are accepted by other classes/modules
which also may store those pointers and have immediate access to the
interpretation results.

My questions:

* I think the code I have is safe with respect to the "static
initialization order fiasco" because the static vector is within the
class itself. Or am I wrong?
* There does not seem to be a way to delete all class
string_interpreter objects from memory if the program terminates. Is
that bad programming? Or is it normal to depend on the dtor of the
vector to delete all the objects in the list?
* Any other bad programming things here?

Thanks,

Jeroen
 
O

Ondra Holub

I have a code like (just some illustrative lines, many things are omitted):

class string_interpreter {
static std::vector<* string_interpreter> my_vector;
*string_interpreter init(const string& s);
... // There's an "operator =" also, and ctor, dtor.

};

*string_interpreter string_interpreter::init(const string& s)
{
// Look in the vector if string 's' was already interpreted.

for (int i = 0; i < vector.length(); ++i)
if (//string 's' is already interpreted)
return vector; // return the result of the interpretation

// Not in the vector, do string interpretation. Store results in the
// class's properties.

...

// Save results in the vector and return.

string_interpreter *new_interpreted_string = new string_interpreter;
*new_interpreted_string = *this;
my_vector.push_back(new_interpreted_string);
return new_interpreted_string;

}

So, basically this class accepts a string, interprets it and stores the
results in its own properties. Then the class makes sure that every
interpreted string (and its results, all within the class itself) is
stored in a vector to ensure that a string needs be interpreted only once.

The reason why I store pointers in the vector and not the objects
itself, is that these pointers are accepted by other classes/modules
which also may store those pointers and have immediate access to the
interpretation results.

My questions:

* I think the code I have is safe with respect to the "static
initialization order fiasco" because the static vector is within the
class itself. Or am I wrong?

Thanks,

Jeroen


Hi.

If you place your static data inside a class as private data, you
still have no guaranty, that it will be initialized before usage,
because any public method of your class may be called during
initialization of other static stuff. So it is simpler to store such
data either as static data in some function (then it is initialized in
first access of this function) or store statically only pointer to
such data and create it dynamically when used for the first time.
* There does not seem to be a way to delete all class
string_interpreter objects from memory if the program terminates. Is
that bad programming? Or is it normal to depend on the dtor of the
vector to delete all the objects in the list?
You can delete static data in function registered with atexit call.
* Any other bad programming things here?
std::vector<* string_interpreter> is wrong, asterisk has to follow
type, e.g. std::vector<string_interpreter*>
 
J

Jojo

Ondra Holub schreef:
I have a code like (just some illustrative lines, many things are omitted):

class string_interpreter {
static std::vector<* string_interpreter> my_vector;
*string_interpreter init(const string& s);
... // There's an "operator =" also, and ctor, dtor.

};

*string_interpreter string_interpreter::init(const string& s)
{
// Look in the vector if string 's' was already interpreted.

for (int i = 0; i < vector.length(); ++i)
if (//string 's' is already interpreted)
return vector; // return the result of the interpretation

// Not in the vector, do string interpretation. Store results in the
// class's properties.

...

// Save results in the vector and return.

string_interpreter *new_interpreted_string = new string_interpreter;
*new_interpreted_string = *this;
my_vector.push_back(new_interpreted_string);
return new_interpreted_string;

}

So, basically this class accepts a string, interprets it and stores the
results in its own properties. Then the class makes sure that every
interpreted string (and its results, all within the class itself) is
stored in a vector to ensure that a string needs be interpreted only once.

The reason why I store pointers in the vector and not the objects
itself, is that these pointers are accepted by other classes/modules
which also may store those pointers and have immediate access to the
interpretation results.

My questions:

* I think the code I have is safe with respect to the "static
initialization order fiasco" because the static vector is within the
class itself. Or am I wrong?

Thanks,

Jeroen


Hi.

If you place your static data inside a class as private data, you
still have no guaranty, that it will be initialized before usage,
because any public method of your class may be called during
initialization of other static stuff. So it is simpler to store such
data either as static data in some function (then it is initialized in
first access of this function) or store statically only pointer to
such data and create it dynamically when used for the first time.


For the last option, is that not also impossible due to the "static
initialization order fiasco"? I assume you suggest in the class a pointer:

static std::vector<string_interpreter *> *vector_ptr;

And at first usage you test:

if (!vector_ptr)
vector_ptr = new ...

But you cannot test on 'vector_ptr' because it may not be initialized,
just like the code I had originally...

So I could add a private method like (got the 'stars' * right this time,
I hope...):

std::vector<string_interpreter *> *string_interpreter::get_vector_ptr()
const
{
static std::vector<string_interpreter *> my_vector;

return &my_vector;
}

? And use that method to access the vector...
You can delete static data in function registered with atexit call.

I'll take a look at that, thanks.
 
O

Ondra Holub

But you cannot test on 'vector_ptr' because it may not be initialized,
just like the code I had originally...

Static data (which is not defined in any function) is automatically
initialized to 0, so you can test it for 0 and initialize it. This is
valid only for static data defined in any class/struct or in global
scope.

So code could look like:
-- cut here --
#include <cstdlib>
#include <iostream>

class A
{
public:
~A()
{
std::clog << "A::~A()\n";
}

// Access method for static data
static A& GetInstance()
{
if (instance == 0)
{
instance = new A();

if (atexit(&A::CleanUp) != 0)
{
std::cerr << "Cannot register CleanUp function!\n";
exit(1);
}
}

return *instance;
}

void Method()
{
std::cout << "A::Method() called\n";
}

private:
A()
{
std::clog << "A::A()\n";
}

static void CleanUp()
{
delete instance;
}

static A* instance;
};

A* A::instance;

int main()
{
std::cout << "Start of main\n";

A::GetInstance().Method();
A::GetInstance().Method();

std::cout << "End of main\n";
}
-- cut here --

And will produce following output:
-- cut here --
Start of main
A::A()
A::Method() called
A::Method() called
End of main
A::~A()
-- cut here --
 
J

Jojo

Ondra Holub schreef:
Static data (which is not defined in any function) is automatically
initialized to 0, so you can test it for 0 and initialize it. This is
valid only for static data defined in any class/struct or in global
scope.

So code could look like:
-- cut here --
#include <cstdlib>
#include <iostream>

class A
{
public:
~A()
{
std::clog << "A::~A()\n";
}

// Access method for static data
static A& GetInstance()
{
if (instance == 0)
{
instance = new A();

if (atexit(&A::CleanUp) != 0)
{
std::cerr << "Cannot register CleanUp function!\n";
exit(1);
}
}

return *instance;
}

void Method()
{
std::cout << "A::Method() called\n";
}

private:
A()
{
std::clog << "A::A()\n";
}

static void CleanUp()
{
delete instance;
}

static A* instance;
};

A* A::instance;

int main()
{
std::cout << "Start of main\n";

A::GetInstance().Method();
A::GetInstance().Method();

std::cout << "End of main\n";
}
-- cut here --

And will produce following output:
-- cut here --
Start of main
A::A()
A::Method() called
A::Method() called
End of main
A::~A()
-- cut here --

Sorry, but I'm lost here... In my original post I coded something like:

class A {
static std::vector<A> my_vector;

// rest of class omitted
};

And you replied:
"If you place your static data inside a class as private data, you
still have no guaranty, that it will be initialized before usage,
because any public method of your class may be called during
initialization of other static stuff."
So I can understand the solution to put the static vector in a method of
class A (like I tried to give an example for in my last post). Or was
that attempt of me not correct?

In your example you have:

class A {
static A* instance; // Vector or just A* does not matter here....

// rest of class omitted
};

and suddenly it is OK to use the value of 'instance' in a public method
("if (instance == 0)" in "GetInstance()"). I don't see differences in
the two pieces of code regarding to the possible crash... If you rely on
the fact that 'instance' is initialized when you first use it in a
public method, why can't you rely on the same initialization for
'my_vector'?

Jeroen
 
T

tony_in_da_uk

Hi Jojo,

Maybe I'm missing the point - I found you question unclear - but a few
brief thoughts from which you might find something useful:

- if you're basically mapping from a string identifier to some
calculated ("interpreted") value, then it's typical to use a hash or
map rather than a vector with some unintuitive test to see if the
element relates to the key
- if you're concerned about order of initialisation, then look on
Google for a decent singleton pattern implementation that you can use
for all such cases, rather than wondering whether some particular hack
is safe
- do you realise that these static initialisation issues overlap
with issues around starting threads from other static objects? You
might want to do some reading around the issues too.
- to ensure a container deletes objects stored externally, use a smart
pointer such as std::auto_ptr<>, or one of the boost library offerings

Cheers,

Tony
 
T

terminator

I have a code like (just some illustrative lines, many things are omitted):

class string_interpreter {
static std::vector<* string_interpreter> my_vector;
*string_interpreter init(const string& s);
... // There's an "operator =" also, and ctor, dtor.

};

*string_interpreter string_interpreter::init(const string& s)
{
// Look in the vector if string 's' was already interpreted.

for (int i = 0; i < vector.length(); ++i)
if (//string 's' is already interpreted)
return vector; // return the result of the interpretation

// Not in the vector, do string interpretation. Store results in the
// class's properties.

...

// Save results in the vector and return.

string_interpreter *new_interpreted_string = new string_interpreter;
*new_interpreted_string = *this;
my_vector.push_back(new_interpreted_string);
return new_interpreted_string;

}

So, basically this class accepts a string, interprets it and stores the
results in its own properties. Then the class makes sure that every
interpreted string (and its results, all within the class itself) is
stored in a vector to ensure that a string needs be interpreted only once.

The reason why I store pointers in the vector and not the objects
itself, is that these pointers are accepted by other classes/modules
which also may store those pointers and have immediate access to the
interpretation results.

My questions:

* I think the code I have is safe with respect to the "static
initialization order fiasco" because the static vector is within the
class itself. Or am I wrong?
* There does not seem to be a way to delete all class
string_interpreter objects from memory if the program terminates. Is
that bad programming? Or is it normal to depend on the dtor of the
vector to delete all the objects in the list?
* Any other bad programming things here?

Thanks,

Jeroen


put static data in static functions:


struct mystruct{
static mytype & myfunc(void){
static mytype mydata(my_init_params);
return mydata;
};
};


regards,
FM.
 
J

James Kanze

Ondra Holub schreef:

[...]
Sorry, but I'm lost here... In my original post I coded something like:
class A {
static std::vector<A> my_vector;
// rest of class omitted
};
And you replied:
"If you place your static data inside a class as private data, you
still have no guaranty, that it will be initialized before usage,
because any public method of your class may be called during
initialization of other static stuff."
So I can understand the solution to put the static vector in a method of
class A (like I tried to give an example for in my last post). Or was
that attempt of me not correct?
In your example you have:

class A {
static A* instance; // Vector or just A* does not matter here....
// rest of class omitted
};
and suddenly it is OK to use the value of 'instance' in a public method
("if (instance == 0)" in "GetInstance()"). I don't see differences in
the two pieces of code regarding to the possible crash...

std::vector requires dynamic initialization, that the
constructor be run. A pointer doesn't.
If you rely on the fact that 'instance' is initialized when
you first use it in a public method, why can't you rely on the
same initialization for 'my_vector'?

Because there are three different types of initialization (for
objects with static lifetime): zero initialization, static
initialization, and dynamic initialization. The are guaranteed
to take place in that order; zero initialization and static
initialization are guaranteed to take place before a single line
of executable code that you wrote is executed.

If the pointer has no initialization expression, it is zero
initialized, and if the initialization expression is a constant
expression, it is static initialized. In both cases,
initialization is guaranteed to occur before any of the code you
wrote is run.

In a single threaded environment, the easiest way to implement
what you need is to use a simple static function:

std::vector< A >&
A::eek:urVector()
{
static std::vector< A > theOneAndOnly ;
return theOneAndOnly ;
}

Note that this may leave you with an order of destruction
problem, however. To avoid the order of destruction problem as
well, you can use:

std::vector< A >&
A::eek:urVector()
{
static std::vector< A >* theOneAndOnly ;
if ( theOneAndOnly == NULL ) {
theOneAndOnly = new std::vector< A > ;
}
return *theOneAndOnly ;
}

This guarantees that the vector will never be destructed.
 
J

James Kanze

- do you realise that these static initialisation issues overlap
with issues around starting threads from other static objects? You
might want to do some reading around the issues too.

To which one might respond: don't start threads in the
constructors of static objects.
- to ensure a container deletes objects stored externally, use
a smart pointer such as std::auto_ptr<>, or one of the boost
library offerings

Generally, you don't want the singleton object to be deleted,
period. If you do, the obvious solution is to declare it as a
local static variable, and let the compiler take care of things.
There's never any need for (or any advantage with) a smart
pointer here.
 
M

MathWizard

James said:
Ondra Holub schreef:

But you cannot test on 'vector_ptr' because it may not be initialized,
just like the code I had originally...

Static data (which is not defined in any function) is automatically
initialized to 0, so you can test it for 0 and initialize it. This is
valid only for static data defined in any class/struct or in global
scope.
[...]


Sorry, but I'm lost here... In my original post I coded something like:




class A {
static std::vector<A> my_vector;




// rest of class omitted
};




And you replied:
"If you place your static data inside a class as private data, you
still have no guaranty, that it will be initialized before usage,
because any public method of your class may be called during
initialization of other static stuff."
So I can understand the solution to put the static vector in a method of
class A (like I tried to give an example for in my last post). Or was
that attempt of me not correct?




In your example you have:

class A {
static A* instance; // Vector or just A* does not matter here....




// rest of class omitted
};




and suddenly it is OK to use the value of 'instance' in a public method
("if (instance == 0)" in "GetInstance()"). I don't see differences in
the two pieces of code regarding to the possible crash...

std::vector requires dynamic initialization, that the
constructor be run. A pointer doesn't.


If you rely on the fact that 'instance' is initialized when
you first use it in a public method, why can't you rely on the
same initialization for 'my_vector'?

Because there are three different types of initialization (for
objects with static lifetime): zero initialization, static
initialization, and dynamic initialization. The are guaranteed
to take place in that order; zero initialization and static
initialization are guaranteed to take place before a single line
of executable code that you wrote is executed.

If the pointer has no initialization expression, it is zero
initialized, and if the initialization expression is a constant
expression, it is static initialized. In both cases,
initialization is guaranteed to occur before any of the code you
wrote is run.

In a single threaded environment, the easiest way to implement
what you need is to use a simple static function:

std::vector< A >&
A::eek:urVector()
{
static std::vector< A > theOneAndOnly ;
return theOneAndOnly ;
}

Note that this may leave you with an order of destruction
problem, however. To avoid the order of destruction problem as
well, you can use:

std::vector< A >&
A::eek:urVector()
{
static std::vector< A >* theOneAndOnly ;
if ( theOneAndOnly == NULL ) {
theOneAndOnly = new std::vector< A > ;
}
return *theOneAndOnly ;
}

This guarantees that the vector will never be destructed.

--
James Kanze (GABI Software) email:[email protected]
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
OK, thanks again for your reply. I'll go the way you pointed out here...
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top