Dynamic Memory

Pages: 12
@dalawh
The platform doesn't matter: once you've broken the rules of the language, it's anybody's guess what happens. it may act as if it does what you call "right to left evaluation", it may set the computer on fire - it would all be valid behavior of this C++ program.

Because demonstration is sometimes more persuasive that simply pointing out the errors, here's the output of the following program on a few compilers that I have at hand, which is your program with one addition: I will assign values to the contents of the arrays, so you can see what is output:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
#include <new>
using namespace std;
int main(){
    int *p;
    p = new (nothrow) int[5];
    for(int i=0; i<5; ++i) p[i] = i; // added
    cout << p[0] << " - " << p[1] << endl;
    cout << "(1)" << *p << " - (2)" << *(p++) << endl; //p++ changes value

    cout << "----------" << endl;

    int *x;
    x = new (nothrow) int[5];
    for(int i=0; i<5; ++i) x[i] = i; // added
    cout << x[0] << " - " << x[1] << " - " << x[2] << endl;
    cout << "(1)" << *(x++) << " - (2)" << *(x++) << " - (3)" << *x << endl;

    delete[] p;
    delete[] x;

    return 0;
}


Linux 3.1.4 x86_64
gcc 4.6.2
0 - 1
(1)1 - (2)0
----------
0 - 1 - 2
(1)1 - (2)0 - (3)0
*** glibc detected *** ./test: free(): invalid pointer: 0x0000000000602014 ***
<crash>


Intel C++ 11.1
0 - 1
(1)0 - (2)0
----------
0 - 1 - 2
(1)0 - (2)1 - (3)2
*** glibc detected *** ./test: free(): invalid pointer: 0x0000000000606014 ***
<crash>


Clang++ 3.0
0 - 1
(1)0 - (2)0
----------
0 - 1 - 2
(1)0 - (2)1 - (3)2
*** glibc detected *** ./test: free(): invalid pointer: 0x0000000000603014 ***
<crash>


Solaris 10
SunPro C++ 5.8
0 - 1
(1)1 - (2)0
----------
0 - 1 - 2
(1)0 - (2)1 - (3)2


gcc 3.4.6
0 - 1
(1)0 - (2)0
----------
0 - 1 - 2
(1)0 - (2)1 - (3)2


Windows XP
Visual Studio 2010 SP1 Debug Mode
0 - 1
(1)1 - (2)0
----------
0 - 1 - 2
(1)1 - (2)0 - (3)2
<crash>


Visual Studio 2010 SP1 Release Mode
0 - 1
(1)0 - (2)0
----------
0 - 1 - 2
(1)0 - (2)0 - (3)2
Last edited on
Based from what I can see, different compilers give different results?
A logic error is still an error. The sad part, your program will compile, it will run properly and the results may seem correct

Let us assume that << operator is not evaluated from right to left
IIRC, it is not. I don't understand your example, but considerer this
cout << "The answer" << 42 << '\n';

((cout << "The answer") << 42) << '\n'; from left to right.
cout << ("The answer" << (42 << '\n')); from right to left.

The idea is that we are creating a bigger and bigger ostream object. By the time it reaches the semicolon, a complete string has be constructed, in correct order.

Edit: This was in response to http://cplusplus.com/forum/general/58378/#msg314702
I forgot to refresh the page, xP
Last edited on
dalawh wrote:
Based from what I can see, different compilers give different results?

Well, that's what he said all along.

h9uest wrote:
No matter what, even some undefined behaviour manages to escape the compiler checks, a run time error will be reported - e.g. divide by 0.

That's simply not true. Not all undefined behaviour causes runtime errors. In fact, very few of them do.

h9uest wrote:
GCC might gives you a WARNING (Not error, okay? Do you really think ANY compiler will let you get away with an error?)

Warnings exist to indicate potential errors, which should answer your question.
Last edited on
@ne555
Can you explain it based on my code? Your code is simple and I understand that with ease.

@Athar
Since different compilers gives different results, how do I know which is right and/or which is the standard?
The standard says it's undefined behavior, so there is no "right" behavior in this case.
And you get to know that by reading the standard: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf
So basically any program that involves code similar to mines is never "correct"?
To make this suddenly long thread a bit more educational, since even when looking at C and pre-C++11 evaluation rules, many people don't see how that kind of output statement is broken, let's consider this simpified (but still broken) expression: cout << *x << *x++.

According to operator precedence and associativity rules, it parses as the following tree:

                               (ostream&) - cout
                              /
              (ostream&) - <<
             /                \
(ostream&)-<<                  (int) - * - (int*) - x
             \
              (int)- * -(int*)
                              \
                                post++ - (int*) - x
                              /
                    x - (int*)       
(data in the tree flows right-to-left, the tokens in parentheses are the types)

Both <<'s here are member functions of std::ostream, so the rules for evaluation of function calls apply: there is a sequence point before the call to any function, at which point all side-effects of the function's arguments and, for member functions, the expression that yields the object on which it is called, are complete, and there is a sequence point at return from any function, at which point any side-effects that took place within the function are complete.

A "side-effect" in this context is the output to screen (what << is doing) or writing to a variable (what postincrement is doing).

The sequence point at the call to the right (in my tree) << says that before it starts execution, both read from x and evaluation of std::cout (produces a reference to ostream) are done. Neither operation has any side-effects anyway, so it doesn't matter here.

The sequence point at the call to the left << says that before it is called, side-effects from its arguments are complete, that is, the output from the right << is complete and the write to x from the postincrement is complete. It does not put any constraints on which happens first: the first output (which in turn requires the read from x) or the writing to x due to postincrement.

In practice this means that read from x required by the right << may come before or after write to x caused by the postincrement. The standard forbids this by the succinct "the prior value shall be accessed only to determine the value to be stored" (in this case the "prior value" is accessed to be output to screen instead), and the compilers assume that the programmer knows this, and reorder subexpressions, cache and precalculate results, never expecting such hidden data dependencies.

It's an unfortunate failure of many textbooks and courses that expression evaluation in C++ (and in C) is either not taught at all or is taught erroneously (using "right-to-left" or "left-to-right" concepts, which belong to other languages)

@Cubbi
My mind is limited and I am not as advanced as you. That being said, I am confused. Can't tell if "-" is a branch like / and \.

Anyone mind simplifying it to "C++ for dummies" level?
@dalawh to make it really simple: if you use "x++", don't use "x" in any form in the same line (there are exceptions but they are not applicable in this case).
@Cubbi
Thanks for simplifying it, but can you explain why?
@Cubbi:

I was wrong. Sorry for the confusion and I take back all my incorrect comments.
Topic archived. No new replies allowed.
Pages: 12