Expressions without side effects in C ++

You see, what I do not understand, why should there be such rights as the following?

int main() { static const int i = 0; i < i > i; } 

I mean, of course, someone really does not have current programs that have expressions without side effects, since that would be very pointless, and that would facilitate parsing and compiling the language. So why not just ban them? What is the use of really getting a language from this syntax?

Another example:

 int main() { static const int i = 0; int x = (i); } 

What are the actual benefits of such statements?

And things like the most unpleasant parsing. Does anyone declare functions in the middle of other functions? I mean, we got rid of things like a declaration of an implicit function, and the like. Why not just get rid of them for C ++ 0x?

+6
c ++ c ++ 11
source share
7 answers

it will process and compile the language much easier

I don’t understand how to do this. Why is it easier to analyze and compile i < i > i if you need to issue a diagnosis than you need to analyze it, if you are allowed to do everything that is damn good, please, provided that the emitted code has no side effects?

The Java compiler forbids unreachable code (as opposed to code without an effect), which is a mixed blessing for the programmer and requires a little extra work from the compiler than the C ++ compiler requires (basic lock analysis). Should C ++ forbid unreachable code? Probably no. Despite the fact that C ++ compilers, of course, do enough optimization to detect unreachable base blocks, in some cases they can do too much. Should if (foo) { ...} be an illegal unreachable block if foo is a false compile-time constant? What if this is not a compile-time constant, but the optimizer figured out how to calculate the value if it should be legal, and the compiler needs to understand that the reason for its removal is implementation-specific so as not to give an error? More special cases.

someone really doesn't have a program with expressions without side effects in them

Freights. For example, if NDEBUG true, then assert expands to void with no effect. So even more special cases are needed in the compiler to allow some useless expressions, but not others.

The rationale, I believe, is that if it is not used for anything, then (a) the compilers will ultimately throw warnings for things like if (foo) assert(bar); , and (b) such a code would be legal in release, but not in debugging, which just confuses:

 assert(foo) // oops, forgot the semi-colon foo.bar(); 

things like the most unpleasant analysis

That is why he called "annoyance." This is a backward compatibility issue. If C ++ now changes the meaning of these annoying parses, the value of the existing code will change. Not as much existing code as you specify, but the C ++ committee takes a pretty solid line for backward compatibility. If you need a language that changes every five minutes, use Perl; -)

Anyway, it's too late. Even if we had some idea that the C ++ 0x committee missed why some function should be deleted or incompatibly changed, they will not break anything in the FCD if the FCD is not completely wrong.

Please note that for all your sentences, any compiler can give a warning for them (in fact, I do not understand what your problem is with the second example, but, of course, for useless expressions and for annoying analyzes in function bodies). If you are right that no one does it intentionally, warnings will not cause harm. If you are mistaken that no one is doing this on purpose, your reported case for correcting them is incorrect. Warnings in popular compilers can pave the way for function removal, especially since the author standard is largely compiled by compiler authors. The fact that we do not always receive warnings for these things tells me that there is more than you think.

+4
source share

Probably because the ban would then make the specification more complex, which would make the compilers more complex.

+8
source share
  • It is sometimes convenient to enter useless statements into the program and compile them only to make sure that they are legal - for example, that types can be allowed / mapped, etc.

  • In particular, in the generated code (macros, as well as more complex external mechanisms, patterns in which policies or types can introduce meaningless extensions in some cases without an operation), having fewer special incompatible cases to avoid simplifying things

  • There may be some temporarily commented code that removes meaningful use of the variable, but it can be painful to similarly identify and comment on all variables that are not used elsewhere.

  • While in your examples you show that variables are "int" directly above meaningless use, in practice types can be much more complex (for example, operator <()) and whether operations can have side effects unknown to the compiler (for example, functions outside queues), so any advantage is limited to simpler cases.

  • C ++ needs a good reason to break back (and save C).

+3
source share

Why should nothing be considered as a special case? In addition, while the above cases are easy to detect, one can imagine much more complex programs where it is not so simple to determine that there are no side effects.

0
source share

Like an iteration of the C ++ standard, C ++ 0x must be backward compatible. No one can claim that the statements you wrote do not exist in any critical software written / owned by, say, NASA or DoD.

In any case, with respect to your first example, the parser cannot claim that i is a static constant expression and that i < i > i is a useless expression - for example. if i is a template, i < i > i is an "invalid variable declaration" and not a "useless calculation" and is still not a parsing error.

0
source share

The operator may have been overloaded to have side effects such as cout<<i; That is why they cannot be deleted now. On the other hand, C # prohibits the use of expresions without assignment or methods, and I think this is good, because the code makes it more understandable and semantically correct. However, C # was able to prohibit this from the very beginning, which is not in C ++.

0
source share

Expressions without side effects can appear more often than you think in templates and macro codes. If you ever declared std::vector<int> , you created the template code without any side effects. std::vector should destroy all its elements at release if you saved the class for type T This requires, at some point, an expression similar to ptr->~T(); to call the destructor. int has no destructor, so the call has no side effects and is completely removed by the optimizer. It will probably be inside the cycle, then the whole cycle has no side effects, so the whole cycle is deleted by the optimizer.

So, if you have forbidden expressions without side effects, std::vector<int> does not work , for one.

Another common case is assert(a == b) . In releases, you want these statements to disappear, but you cannot redefine them as an empty macro, otherwise expressions such as if (x) assert(a == b); suddenly put the following statement in an if statement - disaster! In this case, assert(x) can be redefined as ((void)0) , which is an expression that has no side effects. Now, the if works correctly in release builds - it just does nothing.

These are just two common cases. There are many more that you probably do not know about. Thus, although expressions without side effects seem redundant, they are actually functionally important. The optimizer will completely remove them so that there is no impact on performance.

0
source share

All Articles