【C / C++ / C#】i++ と ++i の明確な違い、エラーの可能性

# 目に見える違い

**i++** と **++i** の速度の比較検証は今回は行わない。

違いを理解していると透明なエラーに3日3晩悩まされる可能性が減ると思われる。

たとえばこんなコードがあるとする。

## C
 ```c
#include <stdio.h>

int main(int argc, char* argv[])
{
    int i = 0;
    int j = 0;
    
    printf("i++: %d\n", i++);
    printf("++j: %d\n", ++j);
    
    return 0;
}
 ```

 ## C++
 ```cpp
#include <iostream>

int main(int argc, char* argv[])
{
    int i = 0;
    int j = 0;
    
    std::cout << "i++: " << i++ << std::endl;
    std::cout << "++j: " << ++j << std::endl;
    
    return 0;
}
 ```

## C#
 ```c#
public class Hello
{
    public static void Main()
    {
        int i = 0;
        int j = 0;
        
        System.Console.WriteLine("i++: " + i++);
        System.Console.WriteLine("++j: " + ++j);
    }
}
 ```

結果はいくつだろうか？
 
```
i++: 0
++j: 1
```

こうなる。

しかし、こう書くと見かけ上の違いはなくなる。
(以降の説明ではC++のみ)

```cpp
#include <iostream>

int main(int argc, char* argv[])
{
    int i = 0;
    int j = 0;
    
    i++;
    ++j;
    
    std::cout << "i: " << i << std::endl;
    std::cout << "j: " << j << std::endl;
    
    if(i == j)
        std::cout << "一致";

    return 0;
}
```
```
i: 1
j: 1
一致
```

同じだ。

処理速度も最近のコンパイラでは両者最適化が行われ、あまり無い。

## ならどちらでも良いのか？

例えばこんなコードはどうだろう。

```cpp
#include <iostream>
#include <vector>

int main(int argc, char* argv[])
{
    std::vector<int> v = { 11, 22, 33, 44, 55 };
    int i = -1;
    
    while (i++ < std::size(v))
        std::cout << "index[" << i << "] => " << v.at(i) << std::endl;

    return 0;
}
```

int 型のvectorがあり、要素の数は 5 個、indexは最大 4 。
実際、C++においては範囲forを用いれば良い。(※1)
どちらかというと、C言語で書きうるコードだ。

```cpp
while (i++ < std::size(v))
```
とかくと、なにも出力されない。

```cpp
while (++i < std::size(v))
```
と書くと
```
index[0] => 11
index[1] => 22
index[2] => 33
index[3] => 44
index[4] => 55
```
このように出力される。

先のwhileでは何も出力されなかったが。
が、もし仮に直前で i が 4 になっていたとして次のif文に入るとどうなるのか。
```cpp
if(i++ < std::size(v))
    std::cout << v.at(i) << std::endl;
```
```
0x00007FFD257D837A で例外がスローされました (main.exe 内): Microsoft C++ の例外: std::out_of_range
```
これは領域外アクセスエラーになる。

**i++** を使え！
**++i** を使え！
と言うつもりはない。
気を付けるに越したことはない。


<br/>
<br/>

(※1)要素の中身だけが欲しいのなら自分ならこう書くだろう。
```cpp
for(const auto& e : v)
    std::cout << e << std::endl;
```
```
11
22
33
44
55
```
<br />
<br />

投稿の直前にふと思ったこと。
> ```cpp
> #include <iostream>
> #include <vector>
> 
> int main(int argc, char* argv[])
> {
>     std::vector<int> v = { 11, 22, 33, 44, 55 };
>     int i = -1;
>     
>     while (i++ < std::size(v))
>         std::cout << "index[" << i << "] => " << v.at(i) << std::endl;
> 
>     return 0;
> }
> ```
> 
> ```cpp
> while (i++ < std::size(v))
> ```
> とかくと、なにも出力されない。

何も表示されないのはおかしくないか？
try / catchで捕まえてみる。
```cpp
#include <iostream>
#include <vector>

int main(int argc, char* argv[])
{
    std::vector<int> v = { 11, 22, 33, 44, 55 };
    int i = -1;

	try
	{
		while (i++ < std::size(v))
			std::cout << "index[" << i << "] => " << v.at(i) << std::endl;
	}
	catch (const std::out_of_range& e)
	{
		std::cerr << "Caught std::out_of_range: " << e.what() << std::endl;
	}
	catch (...)
	{
		std::cerr << "Unknown Error" << std::endl;
	}

    return 0;
}
```
```

```
なにも出ない。
whileを2か所に増やしてみる。
```cpp
try
{
	while (i++ < std::size(v))
		std::cout << "index[" << i << "] => " << v.at(i) << std::endl;
	while (i++ < std::size(v))
		std::cout << "index[" << i << "] => " << v.at(i) << std::endl;
}
catch (const std::out_of_range& e)
{
	std::cerr << "Caught std::out_of_range: " << e.what() << std::endl;
}
catch (...)
{
	std::cerr << "Unknown Error" << std::endl;
}
```
```
index[1] => 22
index[2] => 33
index[3] => 44
index[4] => 55
index[5] => Caught std::out_of_range: invalid vector subscript
```
捕まった。

```cpp
if(-1 < std::size(v))
if(-1 < v.size())
```
とやってもtrueが返らなかったので、size()になにかありそうだ。
長くなりそうなのでまた次回。