Topic: ?Re: 5.2.2/8 unspecified evluation oder?
Author: "Martin Bonner" <martinfrompi@yahoo.co.uk>
Date: Mon, 8 Aug 2005 13:47:55 CST Raw View
Francis Glassborow wrote:
> In article <IKtBL6.1sI2@beaver.cs.washington.edu>, "Andrei Alexandrescu
> (See Website For Email)" <SeeWebsiteForEmail@moderncppdesign.com> writes
> >So today's machines already enjoy the freedom of evaluating code
> >out-of-order, but in a safe and predictable manner. They do it, and
> >they do it with predictable visible semantics. Leaving a dangerous hole
> >in the language when the benefit is safely reaped anyway -- that's just
> >longer justified.
>
> I would be much more convinced if a major compiler (preferably G++ or
> Comeau) gave the guarantee as an extension because I always feel very
> insecure about making changes based on belief on what can be achieved.
>
> I normally argue the other side of this issue but I want to see the
> proponents produce stronger arguments for it.
That seems reasonable.
> BTW, one thing that does concern me is that too many people confuse
> order of evaluation issues with problems of side effects and sequence
> points. Guaranteeing order of evaluation does not solve the side-effects
> issue.
Could you expand upon that? I was certainly under the impression that
the idea was that every operator/punctuator would imply a sequence
point. (With the as-if rule used to allow optimization.) There
doesn't seem much point if we can't AT LEAST plug the
"f(auto_ptr,auto_ptr)" hole.
--
Martin Bonner
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kuyper@wizard.net
Date: 3 Aug 2005 23:00:20 GMT Raw View
Hyman Rosen wrote:
> kuyper@wizard.net wrote:
> > "this is a language without training wheels - it's not for you"
>
> This is what one says about features which are powerful but easy
> to misuse.
I agree, this isn't a feature that makes the language more powerful,
and it would be difficult to attach a meaning to the concept of
"misusing" it. You don't use it; you cope with it. And what you have to
do to cope with it generally makes your programs easier to understand.
> ... It is not what one says about misfeatures which are
> useless but easy to stumble over. ...
This is neither useless, nor unusually easy to stumble over. The
constructs in C++ that guarantee a specific order of operation are few;
the concept that the order is unspecified except when using those
constructs is not very difficult to absorb. I'll admit that sequence
points have many tricky aspects, but it's easy enough to adopt a
programming style where the tricky parts of sequence points don't cause
problems, and that style has the side benefit that it generally makes
your code easier to understand.
> ... You want to have a chainsaw
> without a guard, fine, but there's no reason for the handle to
> have sharp bits that slice up your fingers.
If you drop a chainsaw on your feet, unless you're wearing steel-toed
shoes you probably could get hurt even if it does have a guard, just
because it's fairly heavy. That would be a better analogy for this
feature.
.
> It would be one thing if the language feature contributed
> something useful, but it doesn't.
That's precisely the point of our disagreement.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kuyper@wizard.net
Date: Thu, 4 Aug 2005 11:13:17 CST Raw View
Hyman Rosen wrote:
> kuyper@wizard.net wrote:
> > The constructs in C++ that guarantee a specific order of operation are few;
>
> Really? Let's count some.
>
> 1) Sequence of statements:
> f(); g(); h();
>
> 2) Comma operator (but not if user-defined!):
> f(), g(), h();
>
> 3) Initializers:
> int a = f(), b = g(), c = h();
> int a[] = { f(), g(), h() };
>
> 4) Constructors:
> struct s { int a, b, c; s() : a(f()), b(g()), c(h()) { } };
>
> 5) Function arguments:
> p = strchr(++p, '.');
>
> 6) Short-circuited boolean operators (but not if user-defined!):
> f() && g() || h();
>
> 7) ternary operator:
> f() ? g() : h();
>
> 8) Control constructs:
> if (f()) g();
> while (f()) g();
> do f(); while(g());
>
> 9) Combinations of user-defined operators (but not built-in ones!):
> struct x { x &operator++(int) { return *this; }
> x &operator=(const x &) { return *this; } };
That's just a special case of item 5 on your list. Use of user-defined
operator overloads is the equivalent of calling the corresponding
functions, and imposes precisely the same ordering requirements that
would be imposed by explicitly making the corresponding function calls.
> x a;
> a++ = a;
>
> And I've probably missed a few.
I don't think you've missed many; my copy of the standard is at home,
so I can't check right now. As I said, the number of such constructs is
pretty small.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: "msalters" <Michiel.Salters@logicacmg.com>
Date: Thu, 4 Aug 2005 12:08:13 CST Raw View
Hyman Rosen schreef:
> kuyper@wizard.net wrote:
> > The constructs in C++ that guarantee a specific order of operation are few;
>
> Really? Let's count some.
>
.
> 5) Function arguments:
> p = strchr(++p, '.');
You mean evaluation of all parameters before execution, I guess?
Evaluating ++p and '.' is not ordered. (Of course, evaluating '.'
is trivial).
I'd have to lookup whether initialisation of the actual parameters
is ordered, though. I.e. when calling f(X,int) with a Y() object,
how can the calling Y::Y() and X::X(Y) interleave with the other
operations?
Regards,
Michiel Salters
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: "Martin Bonner" <martinfrompi@yahoo.co.uk>
Date: Fri, 29 Jul 2005 17:26:43 CST Raw View
Marc Schoolderman wrote:
> void f(const foo& obj)
> {
> std::cout << obj.f() << obj.f() << obj.f() << std::endl;
> }
>
> is perfectly okay. If obj.f() would modify the observable state of the
> object, this would either be caught at compiletime, or be indicative of
> problems in the class that will probably crop up elsewhere too.
Unless foo::f is defined as:
int foo::f()
{
static int counter = 0;
return ++counter;
}
. or realistically, if f does not alter the object it is called on,
but DOES alter something in the wider world.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kuyper@wizard.net
Date: Mon, 1 Aug 2005 12:26:04 CST Raw View
Hyman Rosen wrote:
> You are assuming that it is perfectly obvious that
> f(); f(); f();
> should result in a completely defined order while
> p(f(), f(), f());
> equally obviously must have an unspecified order,
I don't see that he used either of those assumptions.
> and that it is laziness
> to expect the latter to operate like the former.
I wouldn't say it's obvious. You have to read and understand either a
decent C++ textbook, or the C++ standard, to reach that conclusion (and
since the standard isn't designed as a textbook, I wouldn't recommnend
the latter method). However, I don't think he was addressing his
comments to those who were unaware of what the standard currently says.
I think he was saying that it's laziness to know what the standard
currently says, and want it changed so that you don't have to
explicitly specify the order when it's important to you that
expressions be executed in a particular order.
> ... But that is not obvious
> at all. It's merely a historical accident that things currently work like
> this. And the reason we should require that there *always* is a defined
> order is that programming languages are the means by which we instruct
> computers what to do, and permitting ambiguity in the language is useless
> and can only lead to error.
It's not useless, which is why it's not an historical accident. You
might argue that it's not useful enough to justify the deliberate
decision to leave the order unspecified; you might even be right, but
you haven't successfully argued that case yet.
Whenever the order is unspecified, it gives implementations the freedom
they need to choose whichever order works best, according to what the
compilers knows about the context and the target computer's
architecture. If the programmer knows something that the compiler can't
know, which makes it important that the expressions be evaluated in a
specific order, the current language contains all of the features you
need to force a particular order of evaluation.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kanze@gabi-soft.fr
Date: 1 Aug 2005 22:10:01 GMT Raw View
"Bo Persson" wrote:
> "Martin Bonner" <martinfrompi@yahoo.co.uk> skrev i meddelandet
> news:1122649512.879866.38000@g44g2000cwa.googlegroups.com...
> > Marc Schoolderman wrote:
> >> void f(const foo& obj)
> >> {
> >> std::cout << obj.f() << obj.f() << obj.f() << std::endl;
> >> }
> >> is perfectly okay. If obj.f() would modify the observable
> >> state of the object, this would either be caught at
> >> compiletime, or be indicative of problems in the class that
> >> will probably crop up elsewhere too.
> > Unless foo::f is defined as:
> > int foo::f()
> > {
> > static int counter = 0;
> > return ++counter;
> > }
> > . or realistically, if f does not alter the object it is
> > called on, but DOES alter something in the wider world.
> But it still boils down to the same question:
> Why should we require that there *always* is a defined order?
Because we want our tests to mean something. Because we want
any problems to be reproduceable, and to show up immediately,
regardless of compiler options.
Because, in the end, we want reliable software, that stays
reliable even through modifications and updates.
--
James Kanze GABI Software
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
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kuyper@wizard.net
Date: Mon, 1 Aug 2005 17:58:56 CST Raw View
Hyman Rosen wrote:
.
> No, the handiness is just a convenient side effect of the real reason
> we must specify the order, which is that no one understands the current
> rules or gets them right, when they even realize that there is something
> to worry about. And that goes for experts and novices alike, as we have
> seen over and over again in this newsgroup.
Yes, there are cases where even experts disagree about what ordering
requirements the standard imposes. However, you don't need to
understand those cases to avoid the problem. The rule is simple: avoid
the tricky cases. The tricky cases almost always involve code that
would still be considered badly written, even if the order were
well-defined. If you're not sure whether the standard requires that one
expression be evaluated before another, put them in seperate statements
to ensure that they are evaluated in the required order.
In general, this will improve the readability of your code. Of course,
if there are lots of places where you aren't sure of what order the
standard imposes, your code could start to look ridiculous. However, if
that's your current level of understanding of C++, then make sure your
code looks ridiculous. Training wheels look ridiculous too, but if you
need them to ride a bicycle, you should use them. If you never get good
enough to ride a bicycle without them, you should consider using a
tricycle instead. However, that isn't a valid reason for requiring
everyone to use a tricycle.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kuyper@wizard.net
Date: 1 Aug 2005 23:30:05 GMT Raw View
Hyman Rosen wrote:
> kuyper@wizard.net wrote:
> > It's not useless, which is why it's not an historical accident. You
> > might argue that it's not useful enough to justify the deliberate
> > decision to leave the order unspecified; you might even be right, but
> > you haven't successfully argued that case yet.
>
> I will never succeed in arguing my case, because there will always
> be people who insist that there is some architecture somewhere that
> will benefit by arbitrary execution order, and that therefore this
> permissiveness must continue. ...
All you need to do, to counter that argument, is to show that the
number of machines where the benefit is significant is so small that
it's not worth the trouble.
> ... The only way to proceed is to ride
> roughshod over those people and push through the rules regardless.
If the only way you can get something approved is by ignoring opposing
arguments, then it shouldn't be approved.
> > the current language contains all of the features you
> > need to force a particular order of evaluation.
>
> The current language contains all you need to make a total hash of
> your program because of all the little dumb gotchas that show up
> everywhere, and can only be avoided by reading every expert-level
> C++ book you can find. All those features that you can use to force
> a particular order are useless if you don't realize that you need to
> use them to begin with.
That's not exactly an unusual characteristic of those features. Any
feature of the language is useless if you don't realize the need to use
it. If you expect "a b" to put the value of b into a, you're going to
run into trouble because you didn't realize you needed to use an "=" to
achieve that effect. Understanding that a "=" is needed to achieve
assignment of a value is a little more elementary than realizing that a
";" is needed to seperate two expressions that need to be evaluated in
a specified order. But realizing that you need to breaking up
complicated statements into simpler ones with a well-defined order
isn't exactly rocket science. In my experience, the resulting code is
not usually a "total hash"; in fact, it's often much simpler and easier
to understand that the single statement with ill-defined ordering that
it replaces.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kanze@gabi-soft.fr
Date: 2 Aug 2005 16:00:09 GMT Raw View
"Andrei Alexandrescu See Website For Email wrote:
> Hyman Rosen wrote:
> > You are assuming that it is perfectly obvious that
> > f(); f(); f();
> > should result in a completely defined order while
> > p(f(), f(), f());
> > equally obviously must have an unspecified order, and that it is laziness
> > to expect the latter to operate like the former.
> And for that matter (and to make the dichotomy more visible): Why should
> f(), f(), f();
> have a defined order, while
> p(f(), f(), f());
> shouldn't?
Or vice versa, depending on the definition of f and p. If f()
returns a type with a user defined operator,(), the order is not
defined. And of course, p could be a macro evaluating to
nothing, in which case, the second has defined order; if the
names were different (say f(), g(), h()), and p were the name of
a type, we've just declared three functions -- and the order of
any side effects in the declarations *is* well defined.
IMHO, the whole argument is becoming ridiculous. On one hand,
some people are claiming that there might be a machine somewhere
where the freedom to reorder might make a difference, and far
more unlikely, that this difference will be measurable in code
where the compiler could not reorder simply under the as if
rule. Claiming -- to date, no one has ever really shown a case
where it's true.
On the other, you have people arguing for simple predictability,
and meeting intuitive programmer expectations.
> > But that is not obvious at all. It's merely a historical
> > accident that things currently work like this. And the
> > reason we should require that there *always* is a defined
> > order is that programming languages are the means by which
> > we instruct computers what to do, and permitting ambiguity
> > in the language is useless and can only lead to error.
> I entirely agree. To partly address the efficiency argument,
> let me add that today's compilers can still obey sequential
> evaluation of function arguments while often reordering
> operations (to increase instruction-level parallelism) as long
> as they can prove there are no visible dependencies.
Right. And the only time they can't prove that there are
visible dependencies is when functions in other compilation
units are being called, e.g. other much more expensive
operations are going on.
--
James Kanze GABI Software
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
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kuyper@wizard.net
Date: 2 Aug 2005 20:10:04 GMT Raw View
Hyman Rosen wrote:
> kuyper@wizard.net wrote:
> > Yes, there are cases where even experts disagree about what ordering
> > requirements the standard imposes.
>
> No, that's *not* what I'm saying. Experts don't disagree about what
> the standard requires, they just make mistakes. We see that here,
> over and over again.
Yes, they sometimes make mistakes - which result in disagreements.
There are also disagreements that arise not because of any mistakes
that people have made, but because people adopted multiple different
mutually incompatible interpretations of unclear wording in the
standard, which are all arguably compatible with the actual wording.
> > The rule is simple: avoid the tricky cases.
>
> Really? So everyone will realize that calling 'f(auto_ptr, auto_ptr)'
> with 'f(new, new)' is a tricky case and avoid it?
It's certainly something I'd never have tried.
> ... And everyone will
> realize that doing 'cout << Start() << Middle() << Finish()' is a
> tricky case and avoid it?
No, of course not . Just like not everyone will realize that
a = b+c - d+e;
isn't equivalent to
a = (b+c)-(d+e);
I don't think we should cater to the limitations of the least competent
users of the language. At some point we should tell them: "this is a
language without training wheels - it's not for you". There are
languages more suitable than C++ for such people, though I'd expect
them to have a certain amount of trouble even when using the most
user-friendly of languages.
> > If you're not sure whether the standard requires that one expression
> > be evaluated before another, put them in seperate statements to ensure
> > that they are evaluated in the required order.
>
> As I have said, the problem isn't when you're not sure, the problem
> is when you don't even realize that there's a question.
I agree; that's a problem; improved education or a change of profession
is the solution.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kanze@gabi-soft.fr
Date: 25 Jul 2005 19:10:15 GMT Raw View
"Steven T. Hatton" wrote:
> In clause 5.2.2/8 we read: "The order of evaluation of
> arguments is unspecified. All side effects of argument
> expression evaluations take effect before the function is
> entered. The order of evaluation of the postfix expression and
> the argument expression list is unspecified."
> When I originally encountered that fact, it didn't have much
> impact on me. It seemed to simply mean that I shouldn't
> things I had no intention of ever doing. There seemed to be
> some value in leaving this ordering open for the compiler to
> chose the most efficient sequence. Then I encountered this
> article: http://www.gotw.ca/gotw/056.htm
> "2. In your travels through the dusty corners of your company's code
> archives, you find the following code fragment:
> // Example 2
> //
>
> // In some header file:
> void f( T1*, T2* );
>
> // In some implementation file:
> f( new T1, new T2 );
> Does this code have any potential exception safety problems?
> Explain.
> Yes, there are several potential exception safety problems.
> Brief recap: An expression like "new T1" is called, simply
> enough, a new-expression. Recall what a new-expression really
> does (I'll ignore placement and array forms for simplicity,
> since they're not very relevant here):
> - it allocates memory
> - it constructs a new object in that memory
> - if the construction fails because of an exception the allocated
> memory is freed
> So each new-expression is essentially a series of two function
> calls: one call to operator new() (either the global one, or
> one provided by the type of the object being created), and
> then a call to the constructor.
> For Example 1, consider what happens if the compiler decides
> to generate code as follows:
> 1: allocate memory for T1
> 2: construct T1
> 3: allocate memory for T2
> 4: construct T2
> 5: call f()
> The problem is this: If either step 3 or step 4 fails because
> of an exception, the C++ standard does not require that the T1
> object be destroyed and its memory deallocated. This is a
> classic memory leak, and clearly not a Good Thing."
> Do compilers really take advantage of this flexibility?
What flexibility? In the above example, the order of the
operations is the natural order.
Read the article further. Lower down in it are examples where
reordering can cause problems. But this particular example is
just broken, reordering or not.
> How much does it buy? Has the theoretical problem actually
> manifested itself in production code? Would specifying order
> on the evaluation of function arguments impose great hardship
> on implementers? Would it adversely impact execution speed,
> compile time, or code size? How much?
The question has been frequently asked; to date, I've yet to see
any concrete case where reordering would significantly hurt
performance. And while it doesn't affect the example above, the
later examples in the article are, IMHO, killers.
--
James Kanze GABI Software
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
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]