1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

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

Posted at

目に見える違い

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

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

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

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++

#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#

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++のみ)

#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
一致

同じだ。

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

ならどちらでも良いのか?

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

#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言語で書きうるコードだ。

while (i++ < std::size(v))

とかくと、なにも出力されない。

while (++i < std::size(v))

と書くと

index[0] => 11
index[1] => 22
index[2] => 33
index[3] => 44
index[4] => 55

このように出力される。

先のwhileでは何も出力されなかったが。
が、もし仮に直前で i が 4 になっていたとして次のif文に入るとどうなるのか。

if(i++ < std::size(v))
    std::cout << v.at(i) << std::endl;
0x00007FFD257D837A で例外がスローされました (main.exe 内): Microsoft C++ の例外: std::out_of_range

これは領域外アクセスエラーになる。

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



(※1)要素の中身だけが欲しいのなら自分ならこう書くだろう。

for(const auto& e : v)
    std::cout << e << std::endl;
11
22
33
44
55


投稿の直前にふと思ったこと。

#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;
}
while (i++ < std::size(v))

とかくと、なにも出力されない。

何も表示されないのはおかしくないか?
try / catchで捕まえてみる。

#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か所に増やしてみる。

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

捕まった。

if(-1 < std::size(v))
if(-1 < v.size())

とやってもtrueが返らなかったので、size()になにかありそうだ。
長くなりそうなのでまた次回。

1
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?