29.ข้อยกเว้น(Exceptions)ใน c++

Exceptions

ในการเขียนโปรแกรม อาจจะมีบางครั้งที่โปรแกรมเกิดข้อผิดพลาดขึ้น ซึ่งข้อผิดพลาดนี้อาจจะเกิดจากการเขียนโปรแกรมหรืออาจจะเกิดจากสภาพแว้ดล้อมอย่างอื่น เมื่อเกิดข้อผิดพลาดนี้ขึ้นจะทำให้การเขียนโปรแกรมหยุดทำงาน ดังนั้นในภาษา C++ เราสามารถแก้ไขปัญหานี้ได้โดยการใช้ Exception สำหรับควบคุมและจัดการกับข้อผิดพลาดที่เกิดขึ้น ในบทนี้ เราจะพูดเกี่ยวกับการใช้งาน Exception ในภาษา C++

C++ exceptions

Exceptions เป็นวิธีที่จะจัดการกับโปรแกรมเพื่อให้ไปทำอย่างอื่นเมื่อมีข้อผิดพลาดเกิดขึ้น โปรแกรมจะพยายามทำบางอย่างที่เราได้ระบุไว้ ถ้ามีข้อผิดพลาดเกิดขึ้น โปรแกรมจะย้ายไปทำงานอีกส่วนของโปรแกรมที่เรียกว่าฟังก์ชันตัวจัดการ Exceptions มีรูปแบบดังนี้:
try
{
    // statetments
}
catch (exceoption e1)
{
    // exception handler 1
}
catch (exceoption e2)
{
    // exception handler 2
}
...
ถ้าเราไม่ใช้ Exception ในโปรแกรมของเรา มันอาจจะเผชิญกับข้อผิดพลาด เช่น Running time errors หรือ Memory allocation errors มี 3 คำสั่งเกี่ยวกับ Exception คือ throwntry และ catch โดยในบล็อคของคำสั่ง try จะเป็นคำสั่งสำหรับตรวจสอบข้อผิดพลาดขึ้นและถ้าหากเกิดข้อผิดพลาดขึ้น โปรแกรมจะทำการโยน Exception ออกไปยังบล็อคของคำสั่ง catch และในบล็อคของคำสั่ง catch จะต้องมีการตรวจจับ Exception ที่เกิดขึ้น หรือเราสามารถใช้คำสั่ง throw เพื่อโยน Exception ออกไปได้
ต่อไปมาดูตัวอย่างในการจัดการกับ Exception โดยเราจะกำหนดให้โปรแกรมของเรานั้นเกิด Exception ขึ้นเมื่อตัวเลขมีค่าเป็น 0
#include <iostream>

using namespace std;

int main()
{
    int n = 0;
    try
    {
        if (n == 0)
            throw n;
        else
            cout << "n is not zero." << endl;
    }
    catch (int e)
    {
        cout << "An exception occurred: n = " << e << endl;
    }
    return 0;
}
ในตัวอย่าง โปรแกรมนั้นมีการจัดการกับข้อผิดพลาด ในบล็อคคำสั่งของ try โปรแกรมของเราจะตรวจสอบว่า n เป็น 0 เราจะใช้คำสั่ง throw ซึ่งมี n อาร์กิวเมนต์ที่จะส่งต่อไปยังบล็อคคำสั่งของ catch (Handlers function) ประเภทของพารามิเตอร์จะต้องตรงกัน ในตัวอย่างนี้ เราได้ส่ง n ซึ่งเป็นข้อมูบแบบ int ฟังก์ชัน catch จะต้องมีพารามิเตอร์เป็นแบบ int e ด้วยเช่นกัน
An exception occurred: n = 0
นี่เป็นผลลัพธ์การทำงานของโปรแกรม ซึ่งจะทำให้เกิด Exception ขึ้นเพราะตัวเลขในตัวแปร n นั้นมีค่าเป็น 0 โปรแกรมนี้แสดงให้คุณเห็นว่าเราสามารถทำให้เกิด Exception ได้ด้วยคำสั่ง throw
ฟังก์ชัน catch สามารถเป็นฟังก์ชันแบบ Overloaded ได้โดยการที่มันมีประเภทของพารามิเตอร์ที่แตกต่างกัน คอมไพลเลอร์จะทำการตัดสินใจว่าจะส่งไปที่ฟังก์ชันไหนเมื่อโปรแกรมทำงาน Overloaded handlers ได้สร้างขึ้นในรูปแบบเหมือนข้างบน นี่เป็นตัวอย่าง
try
{
    throw 10.0;
}
catch (int e1)
{
    // catch integer exception
}
catch (float e2)
{
    // catch floating point exception
}
catch (string e2)
{
    // catch string exception
}
...
ต่อไปมาดูตัวอย่างในการตรวจจับ Exception แบบ Overloaded catch block โดยโปรแกรมของเราจะเป็นโปรแกรมในการดูข้อมูลในอาเรย์ที่รับค่า Index ของอาเรย์ผ่านทางคีย์บอร์ด นี่เป็นตัวอย่างของโปรแกรม
#include <iostream>
#include <string>

using namespace std;

int main()
{
    string name[] = {"Mateo", "Danny", "Thomas", "John"};
    int i;

    try
    {
        cout << "Enter an array index (0 - 3): ";
        cin >> i;
        if (i < 0)
        {
            throw i;
        }
        if (i >= 4)
        {
            string err_msg = "Array index out of bound.";
            throw err_msg;
        }
        cout << name[i] << endl;

    }
    catch (int n)
    {
        cout << "Exception: negative number (" << n << ")." << endl;
    }
    catch (string n)
    {
        cout << "Exception: " << n << endl;
    }

    return 0;
}
ในตัวอย่าง เราได้ประกาศ String อาเรย์สำหรับเก็บชื่อจำนวน 4 ชื่อ โดยโปรแกรมของเราจะรับค่า Index ของอาเรย์เข้ามาและทำการตรวจสอบ Index นั้นว่าถูกต้องหรือไม่ในบล็อคของคำสั่ง try
if (i < 0)
{
    throw i;
}
การตรวจสอบครั้งแรกเป็นการตรวจสอบว่า Index ของอาเรย์นั้นน้อยกว่า 0 หรือไม่ ถ้าหากใช้ เราทำการโยน Integer exception และส่งตัวเลขดังกล่าวออกไป ในบล็อคของคำสั่ง catch เราได้ทำการตรวจจับสำหรับ Integer exception
if (i >= 4)
{
    string err_msg = "Array index out of bound.";
    throw err_msg;
}
ต่อมาเราได้ทำการตรวจสอบ Index อีกครั้ง ในตอนนี้เราทำการตรวจสอบถ้าหาก Index นั้นมีขนาดมากกว่า Index ของสมาชิกตัวสุดท้ายของอาเรย์ซึ่งเป็นค่าที่ไม่ถูกต้อง เราทำให้เกิด String exception โดยการส่งข้อความผิดพลาดออกไป และในบล็อคคำสั่ง catch เราได้ตรวจจับสำหรับ Exception นี้
Enter an array index (0 - 3): -1
Exception: negative number (-1).

Enter an array index (0 - 3): 5
Exception: Array index out of bound.

Enter an array index (0 - 3): 1
Danny
นี่เป็นผลลัพธ์จากการรันโปรแกรมทั้งสามครั้ง และเราได้กรอก Index เป็น -1 5 และ 1 ตามลำดับ จะเห็นว่าในครั้งแรกนั้นเกิด Exception ขึ้นเพราะว่า Index นั้นเป็นจำนวนเต็มลบ ครั้งที่สองก็เกิดเช่นกันเพราะ Index ที่กรอกเข้ามานั้นมีขนาดใหญ่กว่าอาเรย์ และสุดท้ายเป็นค่าของ Index ที่ถูกต้องและโปรแกรมแสดงชื่อของ Index ดังกล่าว

Standard exceptions

ในภาษา C++ มีไลบรารี่ของ Exceptions มาตรฐานสำหรับการใช้งาน ซึ่งมันจะตัดสินใจอัตโนมัติเมื่อเกิดข้อผิดพลาดขึ้น และจะไปยังส่วนของโปรแกรมที่มีฟังก์ชัน catch ที่เหมาะสม ไลบรารี่สามารถใช้ได้โดยการ include std standard <exception> มายังโปรแกรม
ไลบรารี่มาตรฐานของ Exceptions ในภาษา C++ แสดงดังรายการข้างล่าง:
ExceptionDescription
bad_allocthrown by new on allocation failure
bad_castthrown by dynamic_cast when it fails in a dynamic cast
bad_exceptionthrown by certain dynamic exception specifiers
bad_typeidthrown by typeid
bad_function_callthrown by empty function objects
bad_weak_ptrthrown by shared_ptr when passed a bad weak_ptr
logic_errorerror related to the internal logic of the program
runtime_errorerror detected during runtime
Exception มาตรฐานทั้งหมดในภาษา C++ นั้นถูกสืบทอดมาจากคลาส exception ดังนั้นเราสามารถตรวจจับ Exception มาตรฐานได้โดยใช้คลาสนี้เป็นพารามิเตอร์ในบล็อคคำสั่ง catch ได้ มาดูตัวอย่าง
// bad_alloc standard exception
#include <iostream>
#include <exception>

using namespace std;

int main()
{
    try
    {
        int* myarray= new int[1000];
    }
    catch (exception& e)
    {
        cout << "Standard exception: " << e.what() << endl;
    }
    return 0;
}
ในตัวอย่าง เป็นโปรแกรมในการตรวจจับข้อผิดพลาดที่เกิดจากการจองพื้นที่หน่วยความจำเกิดความผิดพลาด ซึ่งจะ throw bad_alloc exception ขึ้น และเราได้จัดการ Exception ในบล็อคของคำสัง catch และใช้ฟังก์ชัน what() สำหรับชื่อของ Exception
ในบทนี้ คุณได้เรียนรู้เกี่ยวกับ Exception ในภาษา C++ เราได้พูดถึงการจัดการ Exception ที่เกิดขึ้นด้วยคำสั่ง throw และการจัดการ Exception มาตรฐาน ซึ่งมันเป็นวิธีที่เราจะทำให้โปรแกรมของเรามีประสิทธิภาพและยืดหยุ่นกับข้อผิดพลาดต่างๆ ได้ดีที่สุด