Assign Reference to another Referance

C

cpisz

Thats true, but build-in types (pointers, ints, ...) aren't destroyed.

It's all a matter of choosing words. destroyed, gone, zapped, not
there, memory removed, same difference, same effect. You cannot make a
call using that pointer after main exits safely.
 
T

Thomas J. Gritzan

cpisz said:
It's all a matter of choosing words. destroyed, gone, zapped, not
there, memory removed, same difference, same effect. You cannot make a
call using that pointer after main exits safely.

You can. Calls can only be made while the program runs. Cleanup code,
i.e. destructors, can only run while the program runs. Memory of file
scope and static variables is released after the end of the program.
 
F

Francesco S. Carta

You can. Calls can only be made while the program runs. Cleanup code,
i.e. destructors, can only run while the program runs. Memory of file
scope and static variables is released after the end of the program.

Does that mean that the latest version (i.e. making foo a global) is
still a program with a well defined behavior?

foo would be a global, non-built-in object with a dtor guaranteed to
be executed before that any static, non-local built-in variable gets
released, and a raw pointer such as "Singleton*" can be considered a
built-in type, isn't it?

I'll discover tomorrow - more or less - because I've just noted
that...

I could I ever

That should read "how could I ever".
I curious to

And that should read "I'm curious to".

Enough of late-in-the-night-typing dyslexia, good night (where it
applies), see you tomorrow (this doesn't even apply for me... uhm...
see you later).

Have good time,
Francesco
 
C

cpisz

The pointer is never destructed.
Its holding memory is released (maybe by the operation system) _after_
any cleanup code runs.



Thats true, but build-in types (pointers, ints, ...) aren't destroyed.

destroyed, released, no longer available, gone, zapped, poofed. No
sense in arguing over the choice of words. The point is you cannot
safely make a call using a global or static pointer after returning
from main.
 
A

Alf P. Steinbach

* cpisz:
destroyed, released, no longer available, gone, zapped, poofed. No
sense in arguing over the choice of words. The point is you cannot
safely make a call using a global or static pointer after returning
from main.

You can.

It's not a choice of words.

Static POD data is not changed except if your code changes it.

If you have static non-POD objects then that's another matter, because
destructors of such objects are being invoked.

But a POD object, such as a pointer, has no destructor.

As mentioned else-thread (if I recall correctly) there is, however, a potential
problem with shared libraries being unmapped.

But that's OS-specific territory: standard C++ doesn't support shared libraries.


Cheers & hth.,

- Alf
 
C

cpisz

Static POD data is not changed except if your code changes it.
But a POD object, such as a pointer, has no destructor.

So, the value of my static pointer is in memory after a lightning
storm and a power outage much less when the OS decides to clean it up
along with other globals after my program exits? I think not. I don't
even buy that it is there 5 minutes after my return statement is
executed. There is no written guarentee of that. If there is please
cut and paste it.

I am claiming that Windows, Linix, and Unix will indeed clean up or
allow write over of all the memory in which your application resides,
after the application exits the entry function. If what you claimed
was true, you'd be quickly out of memory after 3 or 4 runs of most of
your applications. It is changed, it is no longer valid after the
program exits main!

Instead of this thread growing to 90 posts each containing a different
vocabulary word. Let's please just cut and paste the standard as it
pertains to the initialization and deinitialization of:

static objects in global scope.
global objects.
and both as it pertains to built in types if you like.

I believe, although I don't have the standard with me, that it says C+
+ does not guarentee the initialization order or de-initialization
order of any of the above. They do not exist forever, they cannot, my
PC will not even exist forever. I agree C++ does not define how they
get cleaned up, it does not occur in your code, but after the program
exits and when the OS feels like it. Never the less it will get
cleaned up and we have no control over when and in what order, and
that is what causes the problem.
 
A

Alf P. Steinbach

* cpisz:
So, the value of my static pointer is in memory after a lightning
storm and a power outage much less when the OS decides to clean it up
along with other globals after my program exits?

Don't know what you're trying to say but it doesn't exactly inspire me to try to
guess.

I think not. I don't
even buy that it is there 5 minutes after my return statement is
executed. There is no written guarentee of that. If there is please
cut and paste it.

That's meaningless drivel, sorry.

I am claiming that Windows, Linix, and Unix will indeed clean up or
allow write over of all the memory in which your application resides,
after the application exits the entry function.

AFAIK that's true.

However, for Windows it's undocumented that exiting the entry function causes a
process termination; the documented way is to call an API routine.

And anyway, 'main' isn't the process entry function, and process termination
happens a bit later than the return from 'main'. In between exit from 'main' and
process termination destructors of static objects are called, 'atexit' handlers
are executed, and any additional cleanup required by the runtime library is
performed. These are points where your code can execute and can access static data.

If what you claimed
was true, you'd be quickly out of memory after 3 or 4 runs of most of
your applications. It is changed, it is no longer valid after the
program exits main!

That's meaningless drivel, sorry.

Again, 'main' is not the process entry function.

Instead of this thread growing to 90 posts each containing a different
vocabulary word. Let's please just cut and paste the standard as it
pertains to the initialization and deinitialization of:

static objects in global scope.
global objects.
and both as it pertains to built in types if you like.

I believe, although I don't have the standard with me, that it says C+
+ does not guarentee the initialization order or de-initialization
order of any of the above.

There are some guarantees.

They do not exist forever, they cannot, my
PC will not even exist forever. I agree C++ does not define how they
get cleaned up, it does not occur in your code, but after the program
exits and when the OS feels like it.

At that point no code in your program is executing.

Never the less it will get
cleaned up and we have no control over when and in what order, and
that is what causes the problem.

That's meaningless drivel, sorry.


Cheers & hth.,

- Alf
 
C

cpisz


Please use the code earlier in this post where foo is global.


I thought you claimed that the alleged UB manifests itself by a segfault
in Linux. I would like to see such an example. (This code appeared to
cause no segfault in my quick test.)

Nay, I claimed that it is undefined behavior and as such may or may
not cause a seg fault in linux depending on the alignment of the stars
in the universe. It all depends on which order the memory in which the
foo and m_instance reside, becomes invalid. It may run without a
problem at all, it may not. It could run and be recompiled with one
line of unrelated code added and stop working. It could run on one PC
and not another. It is _undefined_ behavior.
So, it appears the lifetime of the static pointer ends only when the
memory is unmapped from the process space by the OS (storage released).

You are just repeating my own claim back to me.
Except I am not claiming in the specific word you used "unmapped from
process space", but rather simply that, no matter how you'd like to
label it, the OS will make the memory where the static pointer resides
invalid.

I've stopped the execution of it in GCC, I really wish I had written
down the call stack to show you what the heck I am talking about. It
had a special name that was obviously "process cleanup".





I argue that the pointer cannot be considered "destroyed" before its
lifetime ends,

I agree
so it is not "destroyed" while any of the program code still runs,

I agree, depending on what you call "program code".
I am claiming that it is not destroyed before execution is returned
from whatever function you have set to be the entry point of your
application. I have said over and over the probem occurs _after_ your
program exits.

Because, just like the static pointer, a dependant global or static
does not have its destructor called until _after_ your program exits.
If said destructor makes use of the static pointer, the behavior is
undefined!

Are you claiming that the destructor of a global object will never get
called after main returns? Because I know we all agree that is poopy.

I really don't know why everyone is having a hard time wrapping thier
heads around this.
If you claim otherwise, please back up your statements by relevant quotes
from the standard!

It is undefined behavior, as in not defined. There is nothing to
quote.
 
C

cpisz

Instead of this thread growing to 90 posts each containing a different
There are some guarantees.

O comeon Alf, you cannot respond with "that's meaningless drivel" and
prove anything.
Can you please post these guarentess you are claiming?

I'd love for you to make a huge impact on my life and allow for me to
use singletons again. You have once or twice before on other topics.
But all these claims that, "there is no problem" isn't convincing me
of anything. I had a problem, not once, but 5 times!
 
A

Alf P. Steinbach

* cpisz:
O comeon Alf, you cannot respond with "that's meaningless drivel" and
prove anything.

True.

I'm not proving anything by that, just trying to give useful feedback.

I think the reason for the meaningless verbiage was that you confused process
entry function with C/C++ 'main' (if you did you're not alone: the Microsoft
documentation has, as long as I can remember, confused the process entry
function with 'WinMain', of all things), but I may be wrong.

Can you please post these guarentess you are claiming?

One important guarantee wrt. singletons is that, for static objects whose
constructions do not overlap in time, they're destroyed in opposite order of
construction.

If a static object A has a constructor that invokes a constructor of static
object B (construction overlap in time) then the situation is more complex.
Object B is then fully constructed before A is fully constructed, but the
construction of A started first. So what is then the destruction sequence?

In this case B might be a singleton, e.g. a logger, and it stands to reason that
if A uses that singleton in its constructor it might also use that singleton in
its destructor, and so it would be really bad if B was destroyed first. Happily
it's destroyed last, guaranteed. Example:


<code>
#include <iostream>
#include <string>

using namespace std;

struct Tattler
{
string id;
Tattler( string const& s ): id( s ) { cout << id << endl; }
~Tattler() { cout << "~" << id << endl; }
};

struct Logger
{
Tattler t;
Logger(): t( "Logger" ) {}

static Logger& instance()
{
static Logger theInstance;
return theInstance;
}
};

struct Foo
{
Tattler t;
Foo(): t( "Foo" ) { Logger::instance(); }
};

static Foo f;

int main()
{}
</code>

<example>
Foo
Logger
~Foo
~Logger
</example>


Another important guarantee is that zero-initialization of statics is performed
before dynamic initialization.

I'd love for you to make a huge impact on my life and allow for me to
use singletons again. You have once or twice before on other topics.
But all these claims that, "there is no problem" isn't convincing me
of anything. I had a problem, not once, but 5 times!

I'm not sure about what problems you mean.

There are many problems with singletons, and even more with static data that is
not wrapped as singleton.

I guess those problems are discussed further up-thread, but.



Cheers & hth.,

- Alf
 
J

James Kanze

Errors do not have to occur in the process code to be errors.
In a linux environment, the result was a seg fault, which your
boss will not be pleased with no matter how much tech talk you
give him.

The code posted will not cause a seg fault under Linux, or any
other system with a conformant C++ compiler. You're obviously
confusing it with something else.

The code posted is a standard and widely used idiom, and has
never caused problems.
 
J

James Kanze

class Singleton
{
public:
static Singleton & Instance()
{
if( !m_instance )
{
m_instance = new Singleton();
}
return *m_instance;
}
static void DoStuff()
{
int x = 1 + 1;
}
private:
static Singleton * m_instance;
};
Singleton * Singleton::m_instance = 0;
class Foo
{
public:

int main()
{
static Foo foo;
return 0; // Undefined behavior after this line, when program
cleanup occurs!

Sorry, but this is just false. There's absolutely no undefined
behavior in the above code. It's fully conformant, legal and
well defined, and works on every C++ implementation I've tried.
static de-initialization fiasco.

Given that there's only one object in the code (the foo in main)
which is de-initialized, there can be no problem with order.
 
J

James Kanze

This isn't quite accurate. Static variables are "created"
before the start of execution. Or rather... variables aren't
created in C++: they are allocated and initialized, two separate
operations. Variables with static lifetime are allocated before
program execution (although there's no way to see this for a
local static). Variables with static lifetime and static
initialization (like m_instance, here) are initialized before
the start of execution.

And static variables with trivial destructors (which includes
all variables with basic types, and all pointers) have a
lifetime until the end of execution; they will never be
"destructed", and can be freely used anywhere, even in the
destructors of static objects. (Worries about order of
initialization and destruction are one reason to use C style
arrays and strings in certain cases.)
The order of initialization is not defined. foo might get
created before m_instance or vica versa.

Sorry. The order of initialization is well defined here.
First, because m_instance has static initialization, it is
initialized before anything user written code (including
constructors of other static objects) is executed. Secondly
(but this typically won't apply in real code), because
m_instance is in the same translation unit as main, and all
static objects with namespace or class scope in a translation
unit are guaranteed to be initialized either before any
functions in the translation unit are called, or before main is
called. (The implementation gets to choose. In practice, the
first choice isn't implementable, so all implementations use the
second, and a lot of code counts on it.)
Maybe, maybe not. The order of deinitialization is also undefined.

There's only one object with a non-trivial destructor, so
there's no issue of order---how can you define an order between
only one object.
This will happen only when foo gets destroyed, when that
happens isn't defined

It's defined to happen after the code returns from main.

m_instance doesn't have a destructor, so it never gets
destroyed.
Whether or not this occurs before foo is destroyed is
undefined. That is the problem and is the de-initialization
fiasco.

This could be a problem is m_instance were a smart pointer. I
think, however, that even the strongest proponents of smart
pointers would agree that in the case where you don't want to
destruct the pointed to object, you shouldn't use a smart
pointer with a non-trivial destructor. (One could imagine using
a smart pointer which e.g. prevented pointer arithmetic, but
still had a trivial destructor.)
The problem is there are two variables in static or global
space. The destruction of one relies on the other existing.

The reason that there is no problem is that one of these
variables doesn't have a destructor. This is the main reason
why we use a pointer and dynamic allocation, rather than just a
static variable.

[...]
The way to avoid this is to make sure that no global or static
depends on another in its destruction,

Independently of the example, this is a good principle. A
destructor exists to release resources, not to acquire them, and
a destructor (generally) should not do anything which can fail
(allocate memory, close a file, etc.). And in practice, I don't
think that I've ever seen a need for a destructor which uses a
singleton that wasn't used earlier. (That doesn't mean that the
case can't exist, however, and I do design my singletons so that
they work in this case.)
 
J

James Kanze

I'm not so sure, but I think that global objects get created
first of anything else, while static objects get created the
first time that the function they appear in gets called. If
you have "void f() { static Foo foo(); }" and you don't call
f(), then foo shouldn't be created at all, I think.

The formal rules are a bit more complicated, but in practice,
you can count on the following:

-- All objects with static lifetime are zero initialized.
-- All objects with static lifetime and a static initializer
are initialized.
-- All objects at namespace or class scope with static lifetime
are initialized. The order of this initialization is the
order of their definition within a translation unit, and
unspecified between translation units.
-- main is called.

Objects with local scope, static lifetime and dynamic
initialization are initialized the first time program control
flow passes over the definition.

Objects with static lifetime and no destructor, or with a
trivial destructor, are never destroyed. Objects with static
lifetime and a non trivial destructor are destructed in the
reverse order of their construction.

The above rules only hold for a conforming program, of course.
Use features not defined in the standard (e.g. dynamic linking
or threads), and there will generally be more rules---there is
potentially a problem if a dynamically linked object is
unloaded, for example (but that's not a frequent case), or if
you start a thread from the constructor of a static object, or
worse, from a destructor. The rules concerning these are
generally implementation defined.
 
J

James Kanze

So, the value of my static pointer is in memory after a
lightning storm and a power outage much less when the OS
decides to clean it up along with other globals after my
program exits?

The standard specifies the behavior of a conformant
implementation. I don't think any implementation is conformant
when the power is removed. Alteratively: the standard says that
behavior is undefined if resource limits are exceeded. One
generally thinks of things like stack overflow in this regard,
but one can easily argue that the program requires a certain
amount of electricity to run, and if that electricity is not
there, a resource limit has been exceeded.

Either way, the implementation is off the hook.
I think not. I don't even buy that it is there 5 minutes after
my return statement is executed. There is no written guarentee
of that. If there is please cut and paste it.

I don't have my copy of the standard here to cut and paste from,
but it's not a question of time. The fact is that neither in C
nor in C++ is returning from main the end of program execution;
both programs define it as calling exit with the return code,
and define the behavior of exit. Program execution only ends
when this call to exit is finished.
I am claiming that Windows, Linix, and Unix will indeed clean
up or allow write over of all the memory in which your
application resides, after the application exits the entry
function.

And that is obviously wrong. The standard is very clear that
e.g. the standard streams must flush their buffers, the standard
FILE streams (or all FILE streams---I forget) must be closed,
functions registered with atexit must be called and destructors
must be called.
If what you claimed was true, you'd be quickly out of memory
after 3 or 4 runs of most of your applications. It is changed,
it is no longer valid after the program exits main!

The C++ standard doesn't say what happens after the function
exit() has finished; you're no longer in a C++ program, so the
C++ standard has no say about it. The Posix standard, however,
does say that finishing exit is the equivalent of calling _exit,
and that does require that all open files (at the system level)
be closed, all memory affected to the process be released, etc.
But that's irrelevant here, since destructors of static objects
are run as part of exit(). (If you call _exit, under Posix,
your destructors won't be run. Nor will any functions
registered with atexit be called, nor will the buffers of your
standard streams be flushed.)
Instead of this thread growing to 90 posts each containing a
different vocabulary word. Let's please just cut and paste the
standard as it pertains to the initialization and
deinitialization of:
static objects in global scope.
global objects.
and both as it pertains to built in types if you like.

As I said, I don't have my copy of the standard here, but I
paraphrased it fairly closely in another posting. The standard
doesn't talk about "global objects" as such: it defines program
startup and shutdown in terms of object lifetime (static
lifetime), scope, and whether the initialization and destruction
is dynamic or static. (Destruction is static if and only if the
destructor is trivial. Initialization can be dynamic even
without a constructor, since the initialization expression may
require code to be executed.)
I believe, although I don't have the standard with me, that it
says C++ does not guarentee the initialization order or
de-initialization order of any of the above.

See my explinations else thread. The standard spends about a
page defining order of initialization (and specifies that order
of destruction is the reverse of order of initialization). Most
importantly, in this regard, it defines three types of
initialization of objects with static lifetime: zero
initialization, static initialization and dynamic
initialization, which are guaranteed to occur in that order (and
both zero initialization and dynamic initialization my apply to
the same object, e.g. as in:

Singleton* ourInstance = &Singleton::instance() ;

Singleton&
Singleton::instance()
{
if ( ourInstance == NULL ) {
ourInstance = new Singleton ;
}
return *ourInstance ;
}

).
They do not exist forever, they cannot, my PC will not even
exist forever.

No, but they exist as long as your program runs. And your
program doesn't stop running when you return from main.
 
J

James Kanze

[...]
You are just repeating my own claim back to me.
Except I am not claiming in the specific word you used
"unmapped from process space", but rather simply that, no
matter how you'd like to label it, the OS will make the memory
where the static pointer resides invalid.

The wording "unmapped from process space" comes from the Posix
standard. It's guaranteed to happen at the end of exit (or when
_exit is called, or when a signal which terminates the process
is raised). Not before.
I've stopped the execution of it in GCC, I really wish I had
written down the call stack to show you what the heck I am
talking about. It had a special name that was obviously
"process cleanup".

Yes. If you'd looked a little further up, you'd have found a
function named exit. The process doesn't end until that
function has finished running.
 
F

Francesco S. Carta

The formal rules are a bit more complicated, but in practice,
you can count on the following:

 -- All objects with static lifetime are zero initialized.
 -- All objects with static lifetime and a static initializer
    are initialized.
 -- All objects at namespace or class scope with static lifetime
    are initialized.  The order of this initialization is the
    order of their definition within a translation unit, and
    unspecified between translation units.
 -- main is called.

Objects with local scope, static lifetime and dynamic
initialization are initialized the first time program control
flow passes over the definition.

Objects with static lifetime and no destructor, or with a
trivial destructor, are never destroyed.  Objects with static
lifetime and a non trivial destructor are destructed in the
reverse order of their construction.

The above rules only hold for a conforming program, of course.
Use features not defined in the standard (e.g. dynamic linking
or threads), and there will generally be more rules---there is
potentially a problem if a dynamically linked object is
unloaded, for example (but that's not a frequent case), or if
you start a thread from the constructor of a static object, or
worse, from a destructor.  The rules concerning these are
generally implementation defined.

Thanks for pointing out the details.

The good thing I realize is that I knew almost all of that even
before, I just wasn't sure about it and I wasn't able to express it
with the correct wording.

One thing I learned again: wording is important.

I still have to get the current standard. Sooner or later I will.

Have good time,
Francesco
 

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

Forum statistics

Threads
473,774
Messages
2,569,598
Members
45,153
Latest member
NamKaufman
Top