C++ exception context

J

jg

Can someone explain what the standard says about
exception context ? For example, suppose bar() always throw
an exception, is the value of g undefined or 1 after the handler
(empty in this case) returns ?

Thanks
JG

foo()
{
int g=0;
try {
g++;
bar(); // bar() throw an exception
} catch (...)
}
printf("g=%d\n", g);
}
 
I

Ian Collins

jg said:
Can someone explain what the standard says about
exception context ? For example, suppose bar() always throw
an exception, is the value of g undefined or 1 after the handler
(empty in this case) returns ?

Thanks
JG

foo()
{
int g=0;

The scope of g is foo(), so g will be 1.
 
A

Andre Kostur

Can someone explain what the standard says about
exception context ? For example, suppose bar() always throw
an exception, is the value of g undefined or 1 after the handler
(empty in this case) returns ?

Thanks
JG

foo()
{
int g=0;
try {
g++;
bar(); // bar() throw an exception
} catch (...)
}
printf("g=%d\n", g);
}

I'm not sure why you would think that bar() would have any effect on g.
The g++ line would have finished executing before bar() is called. An
exception within a try{} block doesn't somehow invalidate the code that was
executed up to the point of the exception.
 
J

jg

The scope of g is foo(), so g will be 1.

So, for the following, glb will be 2.

int glb=1;

void bar()
{
glb++;
throw 1;
}

foo()
try {
bar();
} catch (...)
}
printf("glb=%d\n", glb);
}


I'm not sure why you would think that bar() would have any effect on g.
The g++ line would have finished executing before bar() is called. An
exception within a try{} block doesn't somehow invalidate the code that was
executed up to the point of the exception.

Since a compiler will allocate g into a register, that same register
may be reused (write/use) by bar(). Well, the value of the register
must be saved before being used by bar(). I am just wondering
how a compiler knows where to restore the value of g....

Thanks.
jg
used by bar(), I am wondering how a hand
 
I

Ian Collins

jg said:
So, for the following, glb will be 2.
Why would it be anything else?
int glb=1;

void bar()
{
glb++;
throw 1;
}



Since a compiler will allocate g into a register, that same register
may be reused (write/use) by bar(). Well, the value of the register
must be saved before being used by bar(). I am just wondering
how a compiler knows where to restore the value of g....
Why would it allocate g into a register? g is a global variable, an
address in memory, that's all.
 
J

James Kanze

Can someone explain what the standard says about
exception context ? For example, suppose bar() always throw
an exception, is the value of g undefined or 1 after the handler
(empty in this case) returns ?
foo()
{
int g=0;
try {
g++;
bar(); // bar() throw an exception
} catch (...)
}
printf("g=%d\n", g);
}

In this case, no. The usual C++ rules apply: values will
reflect all changes before the last sequence point, and none of
the changes after the next one. Anything which changes with no
intervening sequence point is up in the air. Throwing an
exception is a sequence point, but don't forget that the order
of evaluation of an expression is not specified, so something
like the following can be very problematic:

f( g++, bar() ) ;

If bar() throws, g may or may not have been incremented.

Be careful, too, because sequence points only define a partial
ordering. For example, given:
f( auto_ptr( new Toto ), bar() ) ;
one possible ordering is:
tmp = new Toto
bar()
auto_ptr( tmp )
If bar() throws, you've got a memory leak.
 
J

jg

Thanks for answering my questions.

I also played with it and looked at the code generated. It looks
that the variables, even locals, will be stored into memory before
calling bar(), which is within try block and may throw an exception.

In a C program (not C++), a local variable usually stays within a
register
accross a call (a performance advantage over C++); whereas in C++, a
local
variable cannot stay in a register accross a call within a try block.

jg
 
A

Andre Kostur

Thanks for answering my questions.

I also played with it and looked at the code generated. It looks
that the variables, even locals, will be stored into memory before
calling bar(), which is within try block and may throw an exception.

In a C program (not C++), a local variable usually stays within a
register
accross a call (a performance advantage over C++); whereas in C++, a
local
variable cannot stay in a register accross a call within a try block.

That's a compiler quality of implementation issue, not a C++ lanugage
issue.
 
J

James Kanze

jg said:
I also played with it and looked at the code generated. It looks
that the variables, even locals, will be stored into memory before
calling bar(), which is within try block and may throw an exception.
In a C program (not C++), a local variable usually stays
within a register accross a call (a performance advantage over
C++); whereas in C++, a local variable cannot stay in a
register accross a call within a try block.

It depends totally on the implementation, and exceptions have
very little effect here. Different implementations have
different conventions regarding what must be saved across the
context of a function call. Back when I was regularly working
on Intel architecture, for example, the convention was that a
function could use any register it wanted: it only had to
restore BP (the frame pointer), SP (obviously:)) and the
segment registers. A compiler could not leave a value in a
register, and expect it to be there after a function call.
Today, on my Sparc, 16 registers are guaranteed safe, and a
compiler can leave a value in one of them even when calling a
function which may throw.

Exceptions affect optimization in two ways. First, they add
control flow paths which the compiler must take into account.
There are probably cases where this will result in saving a
value to memory, where it would otherwise be left in a register,
but they probably aren't very frequent. Secondly, it means that
any time a function which may throw is called, the stack
structure must be "clean"; it must be possible to walk back up
the stack using standard mechanisms. In practice, I don't think
that this ever affects optimization; I'm not aware of a compiler
that doesn't systematically build a clean stack structure in a
non-leaf function.

Exceptions can also have a positive effect on optimization.
First, because the test for the error condition simply isn't
present in the code of the intermediate functions, and secondly,
because the data used by the exception handling is out of line,
possibly in a separate segment, so the resulting function is
smaller, and more likely to fit into cache.

In practice, both effects seem to be pretty negligeable, and the
choix between exceptions or another error reporting mechanism
should be based on design, without regarding performance. Do
what's right; the probability that it will cause a performance
problem is so low that it's not worth worrying about.
 

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,756
Messages
2,569,540
Members
45,025
Latest member
KetoRushACVFitness

Latest Threads

Top