-1
//win10 vs2017
#include<iostream>
using namespace std;
typedef unsigned int uint;
uint dis[1002][1002];
uint cost[1002][1002];
uint v, e;
int main()
{
    while (cin >> v, v) {
        cin >> e;
        int start, tmn;
        for (int i = 0; i < e; i++)
            cin >> start >> tmn >> dis[start][tmn] >> cost[start][tmn], dis[tmn][start] = dis[start][tmn], cost[tmn][start] = cost[start][tmn];
        cin >> start >> tmn;
    }

    system("pause");
    return 0;
}

When I run this program I get an exception.

enter image description here

I put a breakpoint and found the source of the problem.

cin >> start >> tmn >> dis[start][tmn] >> cost[start][tmn],

But why cannot I write it like that?

John Kugelman
  • 307,513
  • 65
  • 473
  • 519
  • 1
    Maybe your MSVC version is too old to support the [guaranteed evaluation order](https://stackoverflow.com/a/38501596/5376789) in C++17. – xskxzr Jun 03 '18 at 03:00
  • This isn't the issue here, but the `cin >> start >> tmn;` line at the end of the `while` loop doesn't store the values anywhere they'll be used. The `start` and `tmn` variables are re-declared on the next iteration, and might not keep the same value. – Daniel H Jun 03 '18 at 04:58

2 Answers2

3

The reason is that, in the partial statement

cin >> start >> tmn >> dis[start][tmn]

the evaluation of expressions start, tmn, and dis[start][tmn] are unsequenced with respect to each other, or to the first call of the stream's operator>>().

One possible sequencing permits dis[start][tmn] to be evaluated (to obtain a reference to an array element) before calling the relevant operator>>() functions that read start and tmn. In that case start and tmn are uninitialised (since their values have not been read) and accessing their values (necessary to evaluate dis[start][tmn]) gives undefined behaviour.

The solution (which also helps make the code more readable for humans) is to avoid complex expressions that that rely on (or in your case, incorrectly assume) particular orders of evaluation.

Instead of (blech!)

for (int i = 0; i < e; i++)
     cin >> start >> tmn >> dis[start][tmn] >> cost[start][tmn],
         dis[tmn][start] = dis[start][tmn], cost[tmn][start] = cost[start][tmn];

(I've broken the statement into two lines) break the input statement into separate statements - which will be sequenced relative to each other - and avoid using the , operator to achieve other effects in the same statement.

for (int i = 0; i < e; i++)
{
    cin >> start >> tmn;
    cin >> dis[start][tmn] >> cost[start][tmn];

    dis[tmn][start] = dis[start][tmn];
    cost[tmn][start] = cost[start][tmn];
}

It would probably also be a good idea to check that start and tmn are valid, before trying to read dis[start][tmn] and cost[start][tmn].

Although you haven't asked about it, the while (cin >> v, v) probably also does not do what you think it does.

Peter
  • 32,539
  • 3
  • 27
  • 63
  • In C++17 the evaluation order is guaranteed and `cin >> start >> tmn >> dis[start][tmn]` should actually work. Also, I'm not sure what you think the OP thinks `while (cin >> v, v)` does, but I think it reads an unsigned number from `cin` and goes through the loop if the number isn't zero (and a comma does guaranteed sequencing back before even C++11, so it should be guaranteed). – Daniel H Jun 03 '18 at 03:26
  • @Daniel - and before C++17, it gives undefined behaviour in a manner completely consistent with what the OP describes. There are few compilers at present that compile as C++17 by default, and obvious beginners (like here) are unlikely to have enabled C++17. I didn't see any point of explaining C++17 to a beginner who probably won't understand the distinction, let alone be using the latest available compiler or know enough about their compiler to enable that mode. Your interpretation of `cin >> v,v` is also wrong. – Peter Jun 03 '18 at 03:37
  • I mention it because I believe the official Stack Overflow policy is to treat the [tag:c++] tag as referring to the latest version unless otherwise stated, and because if somebody comes across this answer while using C++17 it would be helpful to know this isn't the reason. – Daniel H Jun 03 '18 at 04:53
  • And other than potentially not reading a number if `cin >> v` fails (and then having UB or leaving `v` at the same value, depending on if it had ever been successful), what is wrong with my interpretation of the `while` statement? The only other problem I can think of with my interpretation would be if either `unsigned int` or `std::istream` overrode `operator,`, which I'm pretty sure they don't. Saying it doesn't do what it looks like without explaining is less than useful. – Daniel H Jun 03 '18 at 04:55
  • I'm still hoping you answer my question about `while (cin >> v, v)`; it at least [seems to compile to the code I expect](https://godbolt.org/g/5wXJ2s). Maybe there's an edge case I didn't think of, or it's UB and gcc 8.1 with the options I gave happens to interpret it the way I expect, but I honestly cannot think of anything else. – Daniel H Jun 04 '18 at 20:36
-2

The input sequence must be >>'start', then >>'dis[start][tmn]', but maybe compiler optimize 'dis[start][tmn]' as int&. So before input, the 'dis[start][tmn]' is regarded as int&, thus leading to error.
here is assembly code.
See in evaluation order in Bjarne Stroustrup's homepage.

rsy56640
  • 269
  • 1
  • 3
  • 11
  • 1
    The type of `dis[start][tmn]` is `int`. Maybe you mean lvalue, but what's the relationship with evaluation order? In addition, if you want to share a code in Compiler Explorer, you should click the `Share` menu at the top right corner, and use that link. – xskxzr Jun 03 '18 at 03:06
  • @xskxzr I still believe it's int&, for example, x[2] = *(x+2) is reference. And I mention the order to illustrate 'dis[start][tmn]' is regarded as int& **before** the input operation, thus leading an error(maybe my statement is misleading, I'm sorry). Finally, thanks a lot for your guidance on using StackOverflow (Im a novice here). – rsy56640 Jun 03 '18 at 04:07
  • See [here](http://en.cppreference.com/w/cpp/language/operator_member_access#Built-in_subscript_operator), "The result of this expression has the type T". I still don't see why the type affects the evaluation order. Why is `int&` so special that you **infer** the evaluation happens before the input from the fact that it has type `int&`? – xskxzr Jun 03 '18 at 05:00
  • @xskxzr You're right. And I guess the evaluation of parameters is before function call, but the offset 'start' has not been initialized. Is this right? Please correct me if I am wrong. Thanks in advance. – rsy56640 Jun 03 '18 at 06:50
  • You can see the other answer. – xskxzr Jun 03 '18 at 08:02