C++における例外処理

try-catch文(try-catch statement)

try {

  normal flow (normal processing)

}
catch (・・・) {

  exceptional flow (exception handling)

}

try-catch文(try-catch statement)を使って、例外が発生する可能性のある関数の中で例外を捕捉することもできますし、例外が発生する可能性のある関数を呼び出した関数で例外を捕捉することもできます。

注)必ずしも例外が発生した関数内で、例外を捕捉する必要はありません。
注)例外が発生した場合の処理(exception handling)は、catchブロックの中で行います。
注)例外をthrowしたら、catchブロックで例外を捕捉しますが、throwのある関数内にcatchブロックを置く必要はありません。
注)try-catch文(try-catch statement)を使うことで、例外検知(exception detection)の場所と例外処理(exception handling)の場所を分離することができます。


try-catch文を使わない入力チェック

input_validation1.cpp

#include <cmath>
#include <iostream>
#include <stdexcept>

int main() {
  std::string input;
  std::getline(std::cin, input);
  if (input.empty()) { // 例外検知(exception detection)
    std::cerr << "Input is empty!" << std::endl; // 例外処理(exception handling)
    return -1;
  }
  if (std::stod(input) < 0) { // 例外検知(exception detection)
    std::cerr << "Input is a negative number!" << std::endl; // 例外処理(exception handling)
    return -1;
  }
  std::cout << sqrt(std::stod(input)) << std::endl; // 正常処理(normal processing)
}


try-catch文を使った入力チェック

input_validation2.cpp

#include <cmath>
#include <iostream>
#include <stdexcept>

int main() {
  std::string input;
  std::getline(std::cin, input);
  try {
    if (input.empty()) { // 例外検知(exception detection)
      throw std::invalid_argument("Input is empty!");
    }
    if (std::stod(input) < 0) { // 例外検知(exception detection)
      throw std::invalid_argument("Input is a negative number!");
    }
    std::cout << sqrt(std::stod(input)) << std::endl; // 正常処理(normal processing)
  }
  catch (std::invalid_argument& e) {
    std::cerr << e.what() << std::endl; // 例外処理(exception handling)
  }
}


例外が発生する可能性のある関数の中で例外を捕捉する

例外が発生する可能性のある関数(sqrt)で例外を捕捉されるので、呼び出した関数(main)で例外は発生しません。

try-catch1.cpp

#include <cmath>
#include <iostream>
#include <stdexcept>

void sqrt() {
  std::string input;
  getline(std::cin, input);
  try {
    if (input.empty()) {
      throw "Input is empty!";
    }
    if (std::stod(input) < 0) {
      throw "Input is a negative number!";
    }
    std::cout << sqrt(std::stod(input)) << std::endl;
  }
  catch (std::invalid_argument& exception) {
    std::cerr << "Input is not a number!" << std::endl;
  }
  catch (const char* exception) {
    std::cerr << exception << std::endl;
  }
  std::cout << "END" << std::endl;
}

int main() {
  sqrt(); // sqrt()内で例外が発生しても、その中で捕捉されるので、
  std::cout << "Goodbye!" << std::endl; // 実行される
}

注)catch (const char* exception) {} で、const を外すと正常に動作しないので注意してください。


例外が発生する可能性のある関数を呼び出した関数の中で例外を捕捉する

例外が発生する可能性のある関数(sqrt)から呼び出した関数(main)に例外をthrowして、例外発生時、それ以降の処理を中断するには、呼び出した関数の方でtry-catch文を使います。

try-catch2.cpp

#include <cmath>
#include <iostream>
#include <stdexcept>

void sqrt() {
  std::string input;
  std::cin >> input;
  if (std::stod(input) < 0) {
    throw "Input is a negative number!";
  }
  std::cout << sqrt(std::stod(input)) << std::endl;
}

int main() {
  try {
    sqrt(); // sqrt()内で例外が発生すると、
    std::cout << "Goodbye!" << std::endl; // 実行されない
  }
  catch (std::invalid_argument& exception) {
    std::cerr << "Input is not a number!" << std::endl;
  }
  catch (const char* exception) {
    std::cerr << exception << std::endl;
  }
  std::cout << "END" << std::endl;
}

注)catch (const char* exception) {} で、const を外すと正常に動作しないので注意してください。


throw

throw.cpp

#include <iostream>

class Exception {};

void sub1(double input) {
  try {
    if (input < 0) {
      throw 0;
    }
    std::cout << "Hello!" << std::endl;
  }
  catch (...) {
    std::cerr << "..." << std::endl;
  }
  std::cout << "END" << std::endl;
}

void sub2(double input) {
  try {
    if (input < 0) {
      throw "Exception: Input is negative!";
    }
    std::cout << "Hello!" << std::endl;
  }
  catch (const char* exception) {
    std::cerr << exception << std::endl;
  }
  std::cout << "END" << std::endl;
}

void sub3(double input) {
  try {
    if (input < 0) {
      throw std::exception();
    }
    std::cout << "Hello!" << std::endl;
  }
  catch (std::exception& e) {
    std::cerr << e.what() << std::endl;
  }
  std::cout << "END" << std::endl;
}

void sub4(double input) {
  try {
    if (input < 0) {
      throw Exception();
    }
    std::cout << "Hello!" << std::endl;
  }
  catch (Exception) {
    std::cerr << "Exception!" << std::endl;
  }
  std::cout << "END" << std::endl;
}

int main() {
  sub1(-1);
  sub2(-1);
  sub3(-1);
  sub4(-1);
}


std::stod

catchブロックで捕捉した例外を再度throwしています。

stod.cpp

#include <iostream>
#include <stdexcept>

void sub(std::string input) {
  try {
    std::cout << std::stod(input) << std::endl;
  }
  catch (std::invalid_argument& exception) {
    std::cerr << "Exception: " << exception.what() << std::endl;
    throw;
  }
}

int main() {
  try {
    sub("0.1");
    sub("1.0e+2");
    sub("1.0E-2");
    sub("abc");
    std::cout << "Hello!" << std::endl;
  }
  catch (...) {
    std::cerr << "..." << std::endl;
  }
}


std::bad_alloc

catchブロックで捕捉した例外を再度throwしています。

注)下記のプログラムをclang++でコンパイルして実行すると、バグっぽい挙動を示すので注意してください。g++によるコンパイルを推奨します。

bad_alloc.cpp

#include <iostream>
#include <new>

void sub() {
  double* array1 = NULL;
  double* array2 = NULL;
  try {
    array1 = new double[500000000];
    array2 = new double[500000000];
  }
  catch (std::bad_alloc& exception) {
    std::cerr << "Exception: " << exception.what() << std::endl;
    if (array2 != NULL) delete[] array2;
    if (array1 != NULL) delete[] array1;
    throw;
  }
  if (array2 != NULL) delete[] array2;
  if (array1 != NULL) delete[] array1;
}

int main() {
  try {
    sub();
    std::cout << "Hello!" << std::endl;
  }
  catch (...) {
    std::cerr << "..." << std::endl;
  }
}


参考サイト

広告

C++における名前空間

try-catch文(try-catch statement)

try {

  normal flow (normal processing)

}
catch (・・・) {

  exceptional flow (exception handling)

}

try-catch文(try-catch statement)を使って、例外が発生する可能性のある関数の中で例外を捕捉することもできますし、例外が発生する可能性のある関数を呼び出した関数で例外を捕捉することもできます。

注)必ずしも例外が発生した関数内で、例外を捕捉する必要はありません。
注)例外が発生した場合の処理(exception handling)は、catchブロックの中で行います。
注)例外をthrowしたら、catchブロックで例外を捕捉しますが、throwのある関数内にcatchブロックを置く必要はありません。


try-catch文を使わない場合

without-try-catch.cpp

#include <cmath>
#include <iostream>
#include <stdexcept>

int main() {
  std::string input;
  getline(std::cin, input);
  if (input.empty()) { // -> 例外検知(exception detection)
    std::cerr << "Input is empty!" << std::endl; // -> 例外処理(exception handling)
    return -1;
  }
  if (std::stod(input) < 0) { // -> 例外検知(exception detection)
    std::cerr << "Input is a negative number!" << std::endl; // -> 例外処理(exception handling)
    return -1;
  }
  std::cout << sqrt(std::stod(input)) << std::endl; // -> 通常処理(normal processing)
}


try-catch文を使う場合

try-catch.cpp

#include <cmath>
#include <iostream>
#include <stdexcept>

int main() {
  std::string input;
  getline(std::cin, input);
  try {
    if (input.empty()) { // -> 例外検知(exception detection)
      throw std::invalid_argument("Input is empty!");
    }
    if (std::stod(input) < 0) { // -> 例外検知(exception detection)
      throw std::invalid_argument("Input is a negative number!");
    }
    std::cout << sqrt(std::stod(input)) << std::endl; // -> 通常処理(normal processing)
  }
  catch (std::invalid_argument& e) {
    std::cerr << e.what() << std::endl; // -> 例外処理(exception handling)
  }
}


例外が発生する可能性のある関数の中で例外を捕捉する

例外が発生する可能性のある関数(sqrt)で例外を捕捉されるので、呼び出した関数(main)で例外は発生しません。

try-catch1.cpp

#include <cmath>
#include <iostream>
#include <stdexcept>

void sqrt() {
  std::string input;
  getline(std::cin, input);
  try {
    if (input.empty()) {
      throw "Input is empty!";
    }
    if (std::stod(input) < 0) {
      throw "Input is a negative number!";
    }
    std::cout << sqrt(std::stod(input)) << std::endl;
  }
  catch (std::invalid_argument& exception) {
    std::cerr << "Input is not a number!" << std::endl;
  }
  catch (const char* exception) {
    std::cerr << exception << std::endl;
  }
  std::cout << "END" << std::endl;
}

int main() {
  sqrt(); // -> sqrt()内で例外が発生しても、その中で捕捉されるので、
  std::cout << "Goodbye!" << std::endl; // -> 実行される
}

注)catch (const char* exception) {} で、const を外すと正常に動作しないので注意してください。


例外が発生する可能性のある関数を呼び出した関数の中で例外を捕捉する

例外が発生する可能性のある関数(sqrt)から呼び出した関数(main)に例外をthrowして、例外発生時、それ以降の処理を中断するには、呼び出した関数の方でtry-catch文を使います。

try-catch2.cpp

#include <cmath>
#include <iostream>
#include <stdexcept>

void sqrt() {
  std::string input;
  std::cin >> input;
  if (std::stod(input) < 0) {
    throw "Input is a negative number!";
  }
  std::cout << sqrt(std::stod(input)) << std::endl;
}

int main() {
  try {
    sqrt(); // -> sqrt()内で例外が発生すると、
    std::cout << "Goodbye!" << std::endl; // -> 実行されない
  }
  catch (std::invalid_argument& exception) {
    std::cerr << "Input is not a number!" << std::endl;
  }
  catch (const char* exception) {
    std::cerr << exception << std::endl;
  }
  std::cout << "END" << std::endl;
}

注)catch (const char* exception) {} で、const を外すと正常に動作しないので注意してください。


throw

throw.cpp

#include <iostream>

class Exception {};

void sub1(double input) {
  try {
    if (input < 0) {
      throw 0;
    }
    std::cout << "Hello!" << std::endl;
  }
  catch (...) {
    std::cerr << "..." << std::endl;
  }
  std::cout << "END" << std::endl;
}

void sub2(double input) {
  try {
    if (input < 0) {
      throw "Exception: Input is negative!";
    }
    std::cout << "Hello!" << std::endl;
  }
  catch (const char* exception) {
    std::cerr << exception << std::endl;
  }
  std::cout << "END" << std::endl;
}

void sub3(double input) {
  try {
    if (input < 0) {
      throw std::exception();
    }
    std::cout << "Hello!" << std::endl;
  }
  catch (std::exception& e) {
    std::cerr << e.what() << std::endl;
  }
  std::cout << "END" << std::endl;
}

void sub4(double input) {
  try {
    if (input < 0) {
      throw Exception();
    }
    std::cout << "Hello!" << std::endl;
  }
  catch (Exception) {
    std::cerr << "Exception!" << std::endl;
  }
  std::cout << "END" << std::endl;
}

int main() {
  sub1(-1);
  sub2(-1);
  sub3(-1);
  sub4(-1);
}


std::stod

catchブロックで捕捉した例外を再度throwしています。

stod.cpp

#include <iostream>
#include <stdexcept>

void sub(std::string input) {
  try {
    std::cout << std::stod(input) << std::endl;
  }
  catch (std::invalid_argument& exception) {
    std::cerr << "Exception: " << exception.what() << std::endl;
    throw;
  }
}

int main() {
  try {
    sub("0.1");
    sub("1.0e+2");
    sub("1.0E-2");
    sub("abc");
    std::cout << "Hello!" << std::endl;
  }
  catch (...) {
    std::cerr << "..." << std::endl;
  }
}


std::bad_alloc

catchブロックで捕捉した例外を再度throwしています。

注)下記のプログラムをclang++でコンパイルして実行すると、バグっぽい挙動を示すので注意してください。g++によるコンパイルを推奨します。

bad_alloc.cpp

#include <iostream>
#include <new>

void sub() {
  double* array1 = NULL;
  double* array2 = NULL;
  try {
    array1 = new double[500000000];
    array2 = new double[500000000];
  }
  catch (std::bad_alloc& exception) {
    std::cerr << "Exception: " << exception.what() << std::endl;
    if (array2 != NULL) delete[] array2;
    if (array1 != NULL) delete[] array1;
    throw;
  }
  if (array2 != NULL) delete[] array2;
  if (array1 != NULL) delete[] array1;
}

int main() {
  try {
    sub();
    std::cout << "Hello!" << std::endl;
  }
  catch (...) {
    std::cerr << "..." << std::endl;
  }
}


参考サイト

Javaにおけるclasspathの使い方

classpathは他のディレクトリにあるソールファイルやクラスファイルを参照してコンパイルしたり、他のディレクトリにあるクラスファイルを参照して実行する場合に使います。
尚、importは異なるパッケージに属するクラスを使用する場合に使います。

1.ソースファイルの作成

D:\src\src1\src2\src3\main.java

package src1.src2.src3;
import lib1.lib2.lib3.Sub;

class Main {
  public static void main(String... args) {
    new Sub().sub();
  }
}

D:\lib\lib1\lib2\lib3\Sub.java

package lib1.lib2.lib3;

public class Sub {
  public void sub() {
    System.out.println("Hello!");
  }
}


2.コンパイル

javac0.bat を実行するとクラスファイルが生成されます。

D:\src\javac0.bat(ファイル名をjavac.batにすると暴走します)

set path=D:\jdk\bin
javac -classpath D:\lib src1/src2/src3/*.java


3.実行

下記の java0.bat をダブルクリックすると実行できます。

D:\src\java0.bat(ファイル名をjava.batにすると暴走します)

set path=D:\jdk\bin
java -classpath .;D:\lib src1/src2/src3/Main
pause


参考サイト

1.Javaで自作したクラスをimportしたい