SlideShare a Scribd company logo
1 of 144
Download to read offline
例外安全入門
   @hotwatermorning
自己紹介

●
    @hotwatermorning
●
    はてなid:heisesswasser
●
    大学生
●
    DTMやってます
●
    C++が好きです
●
    「プログラミングの魔導少女」では
    「RangeとPStade.Oven」という記事を書かせ
    ていただきました。
C++erなら
誰しもメモリーリークに
悩まされたことがあるはず
今回のセッションは
その悩みを
軽減する
軽減する
  かもしれない
本日のレシピ

1.例外安全とは?
2.例外安全性の種類
3.例外安全なコードを書くには
4.例外安全にするための技法
本日のレシピ

1.例外安全とは?
2.例外安全性の種類
3.例外安全なコードを書くには
4.例外安全にするための技法

いわゆる、エラーハンドリング/例外ハンドリング関連の内容
●

は含んでおりません。
本日のレシピ

1.例外安全とは?
2.例外安全性の種類
3.例外安全なコードを書くには
4.例外安全にするための技法
● いわゆる、エラーハンドリング/例外ハンドリング関連の内容
は含んでおりません。
●
  というかそれは僕も知りたいので誰か教えt(ry
1.例外安全とは?
例外安全とは?

「あるコード内を実行中の失敗が、メモリリー
ク、格納データの不整合、不正な出力などの有
害な効果を生じないとき、そのコード片は例外
安全であると言う。」
“例外処理”
http://ja.wikipedia.org/wiki/%E4%BE%8B
%E5%A4%96%E5%87%A6%E7%90%86
例外安全とは?

「例外安全なプログラミングとは、 例外を投げ
る可能性があるコードが実際に例外を投げた場
合に、 プログラムの状態が壊れずリソースも
リークしないように作るプログラミングのこと
を言います。 」
“例外安全なプログラミング”
http://www.kmonos.net/alang/d/2.0/exception-safe.html
例外安全とは?

●
    例外が発生しても適切に対処できるよう
    なコードを書く。
●
    適切に対処しないと・・・
     ‣   メモリリーク、リソースリーク
     ‣   中途半端な操作の完了
     ‣   デストラクタから例外が投げられる
          と・・・
例外安全でないコードの例(1)

void SampleClass::ReadData(int n)
{
    delete [] data_;
    data_ = new T[n];
    read_data(data_, n);
}
例外安全でないコードの例(1)

void SampleClass::ReadData(int n)
{
    delete [] data_;
    data_ = new T[n];    //←ここや
    read_data(data_, n);
}
例外安全でないコードの例(1)

void SampleClass::ReadData(int n)
{
    delete [] data_;
    data_ = new T[n];   //←ここや
    read_data(data_, n);//←ここで
}
例外安全でないコードの例(1)

void SampleClass::ReadData(int n)
{
    delete [] data_;
    data_ = new T[n];   //←ここや
    read_data(data_, n);//←ここで
}        //例外が投げられると...??
例外安全でないコードの例(1)

void SampleClass::ReadData(int n)
{
    delete [] data_;
    data_ = new T[n];   //←ここや
    read_data(data_, n);//←ここで
}        //例外が投げられると...??
SampleClassの状態が壊れてしまう!!
例外安全でないコードの例(2)

SampleClass2 &
    SampleClass2::operator=
        (SampleClass2 const &rhs)
{
    data1_ = rhs.data1_;
    data2_ = rhs.data2_;
    data3_ = rhs.data3_;
    data4_ = rhs.data4_;
    return *this;
}
例外安全でないコードの例(2)

SampleClass2 &
    SampleClass2::operator=
        (SampleClass2 const &rhs)
{
    data1_ = rhs.data1_;
    data2_ = rhs.data2_;//このうち
    data3_ = rhs.data3_;
    data4_ = rhs.data4_;
    return *this;
}
例外安全でないコードの例(2)

SampleClass2 &
    SampleClass2::operator=
        (SampleClass2 const &rhs)
{
    data1_ = rhs.data1_;
    data2_ = rhs.data2_;//このうち
    data3_ = rhs.data3_;//どれかで
    data4_ = rhs.data4_;
    return *this;
}
例外安全でないコードの例(2)

SampleClass2 &
    SampleClass2::operator=
        (SampleClass2 const &rhs)
{
    data1_ = rhs.data1_;
    data2_ = rhs.data2_;//このうち
    data3_ = rhs.data3_;//どれかで
    data4_ = rhs.data4_;//例外が起きたら
    return *this;
}
例外安全でないコードの例(2)

SampleClass2 &
    SampleClass2::operator=
        (SampleClass2 const &rhs)
{
    data1_ = rhs.data1_;//これはどうなる?
    data2_ = rhs.data2_;//このうち
    data3_ = rhs.data3_;//どれかで
    data4_ = rhs.data4_;//例外が起きたら
    return *this;
}
例外安全なコードじゃないと
例外が起きたときに
きちんと対処できない
よし、
例外安全なコードを書こう!
と、そのまえに
2.例外安全性の種類
例外安全性の種類

●
  例外を投げない保証     高
●
  強い例外安全
              例外安全性
●
  基本的な例外安全
●
  例外安全保証なし      低
例外安全性の種類

●
  例外を投げない保証
●
  強い例外安全
              但し・・・
●
  基本的な例外安全
●
  例外安全保証なし
例外安全性の種類

●
  例外を投げない保証     高
●
  強い例外安全
               コスト…
●
  基本的な例外安全
●
  例外安全保証なし      低
例外安全性の種類

●
    例外安全保証なし
例外安全性の種類

       ●
           例外安全保証なし
●
    その関数や呼び出し先で例外が起きると
    リソースがリークしてしまうかもしれな
    い・・・
例外安全性の種類

       ●
           例外安全保証なし
void SampleClass::ReadData(int n)
{
    delete [] data_;
    data_ = new T[n];
    read_data(data_, n);
}
例外安全性の種類

●
    基本的な例外安全の保証
例外安全性の種類

     ●
         基本的な例外安全の保証
●
    例外が投げられても、いかなるリソース
    もリークしない。
例外安全性の種類

     ●
         基本的な例外安全の保証
●
    例外が投げられても、いかなるリソース
    もリークしない。
●
    副作用は出るかもしれない(データの変
    更や出力など。)
例外安全性の種類

     ●
         基本的な例外安全の保証
●
    例外が投げられても、いかなるリソース
    もリークしない。
●
    コンテナの中で例外が発生した場合、一
    貫性は保っているが、予測可能な状態と
    は限らない。
●
    なのでその後、削除や再利用はできる。
例外安全性の種類

       ●
           基本的な例外安全の保証
void SampleClass::ReadData(int n)
{
    delete [] data_; data_ = 0;
    try {
        data_ = new T[n];
        read_data(data_, n);
    } catch(...) {
        delete [] data_;    data_ = 0;
    }
}
例外安全性の種類

●
    強い例外安全の保証
例外安全性の種類

      ●
          強い例外安全の保証
●
    例外が起きたなら、全ての変更は
    ロールバックされる
●
    完全な成功か、例外による完全な失
    敗かの2つの状況になる
例外安全性の種類

           ●
               強い例外安全の保証
void SampleClass::ReadData(int n)
{
    T *tmp = data_; data_ = 0;
    try {
        data_ = new T[n];
        read_data(data_, n);
        delete [] tmp;
    } catch(...) {
        delete [] data_; data_ = tmp;
    }
}
例外安全性の種類

●
    例外を投げない保証(no throw)
例外安全性の種類

    ●
        例外を投げない保証(no throw)
●
    操作は全て正しく完了されることが
    保証される。
例外安全性の種類

    ●
        例外を投げない保証(no throw)
●
    操作は全て正しく完了されることが
    保証される。
●
    例)基本データ型の代入などは例外
    が起きない
例外安全性の種類

    ●
        例外を投げない保証(no throw)
●
    操作は全て正しく完了されることが
    保証される。
●
    例)基本データ型の代入などは例外
    が起きない
●
    呼び出し先も例外を投げない保証が
    できなければならない
例外安全性の種類

●
    例外を投げない保証(no throw)
void foo()
{
    int n1 =   0x10;
    int n2 =   n1;
    int *pn1   = &n1;
    int *pn2   = pn1;
}
3.例外安全なコードを書くには
例外安全なコードを書くには

●
    ある実行パス中の例外安全性は、その工
    程で一番低いものになる。
例外安全なコードを書くには

●
    ある実行パス中の例外安全性は、その工
    程で一番低いものになる。
●
    どゆこと?
例外安全なコードを書くには

int baz() { return bar() * bar(); }
void foo()
{
    int n1 = 1;     //例外安全なコード
    int n2 = bar(); //例外安全でないコード
    int n3 = 3;     //例外安全なコード
    int n4 = baz(); //例外安全でないコード
}
例外安全なコードを書くには
(さっきの「強い例外安全」のサンプルコード)

void SampleClass::ReadData(int n)
{
    T *tmp = data_; data_ = 0;
    try {
        data_ = new T[n];
        read_data(data_, n);
        delete [] tmp;
    } catch(...) {
        delete [] data_; data_ = tmp;
    }
}
例外安全なコードを書くには
(さっきの「強い例外安全」のサンプルコード)

void SampleClass::ReadData(int n)
{
    T *tmp = data_; data_ = 0;
    try {
        data_ = new T[n];
        read_data(data_, n); //←もしこの関数が
        delete [] tmp;
    } catch(...) {
        delete [] data_; data_ = tmp;
    }
}
例外安全なコードを書くには
(さっきの「強い例外安全」のサンプルコード)

void SampleClass::ReadData(int n)
{
    T *tmp = data_; data_ = 0;
    try {
        data_ = new T[n];
        read_data(data_, n); //←もしこの関数が
        delete [] tmp;       //例外安全じゃないと
    } catch(...) {
        delete [] data_; data_ = tmp;
    }
}
例外安全なコードを書くには
(さっきの「強い例外安全」のサンプルコード)

void SampleClass::ReadData(int n)
{
    T *tmp = data_; data_ = 0;
    try {
        data_ = new T[n];
        read_data(data_, n); //←もしこの関数が
        delete [] tmp;       //例外安全じゃないと
    } catch(...) {           //ReadData関数は
        delete [] data_; d...//完全な例外安全とは
    }                        //言えなくなる
}
例外安全なコードを書くには

●
    ある実行パス中の例外安全性は、その工
    程で一番低いものになる。
●
    呼び出し先の例外安全性にも左右されて
    しまう。
例外安全なコードを書くには

●
    ある実行パス中の例外安全性は、その工
    程で一番低いものになる。
●
    呼び出し先の例外安全性にも左右されて
    しまう。
●
    プログラムの中で基本的な機能であるほ
    ど、しっかりした例外安全性を実装して
    いなければならない。(コンテナなど)
例外安全なコードを書くには

●
    ある実行パス中の例外安全性は、その工
    程で一番低いものになる。
●
    呼び出し先の例外安全性にも左右されて
    しまう。
●
    プログラムの中で基本的な機能であるほ
    ど、しっかりした例外安全性を実装して
    いなければならない。(コンテナなど)
●
    標準のコンテナは大体強い保証を満たす
例外安全なコードを書くには

●
    それぞれの関数で例外を投げうる部分と
    投げない部分を明確に分離する。
●
    本来の処理の成功を確認した時点で、例
    外を投げない部分を使って、状態の変更
    と後処理を行うようにする。
例外安全なコードを書くには

●
    例外中立について
例外安全なコードを書くには
void SampleClass::ReadData(int n)
{
    T *tmp = data_; data_ = 0;
    try {
        data_ = new T[n];
        read_data(data_, n);
        delete [] tmp;
    } catch(...) {
        delete [] data_; data_ = tmp;
    }
}
例外安全なコードを書くには
void SampleClass::ReadData(int n)
{
    T *tmp = data_; data_ = 0;
    try {
        data_ = new T[n];
        read_data(data_, n);
        delete [] tmp;
    } catch(...) {
        delete [] data_; data_ = tmp;
    }   //例外安全に書けましたね!
}
例外安全なコードを書くには
void SampleClass::ReadData(int n)
{
    T *tmp = data_; data_ = 0;
    try {
        data_ = new T[n];
        read_data(data_, n);
        delete [] tmp;
    } catch(...) {
        delete [] data_; data_ = tmp;
    }   //でもいざ例外が起きたときに
}
例外安全なコードを書くには
void SampleClass::ReadData(int n)
{
    T *tmp = data_; data_ = 0;
    try {
        data_ = new T[n];
        read_data(data_, n);
        delete [] tmp;
    } catch(...) {
        delete [] data_; data_ = tmp;
    }   //ReadDataの呼び出し元は
}       //ここで起きた例外をなにも知らない
例外安全なコードを書くには

●
    例外中立について
●
    コンテナなどで例外が起きると、その例
    外が起きるまでのコンテキストを知って
    いるのは呼び出し元だけ。
例外安全なコードを書くには

●
    例外中立について
●
    コンテナなどで例外が起きると、その例
    外が起きるまでのコンテキストを知って
    いるのは呼び出し元だけ。
●
    コンテナでは、自分の行った範囲の例外
    は安全に処理できるけど、他は無理。
例外安全なコードを書くには

●
    例外中立について
●
    コンテナなどで例外が起きると、その例
    外が起きるまでのコンテキストを知って
    いるのは呼び出し元だけ。
●
    コンテナでは、自分の行った範囲の例外
    は安全に処理できるけど、他は無理。
●
    適切に処理できるところまでは例外を正
    しく伝える。
例外安全なコードを書くには
void SampleClass::ReadData(int n)
{
    T *tmp = data_; data_ = 0;
    try {
        data_ = new T[n];
        read_data(data_, n);
        delete [] tmp;
    } catch(...) {
        delete [] data_; data_ = tmp;
    }
}
例外安全なコードを書くには
void SampleClass::ReadData(int n)
{
    T *tmp = data_; data_ = 0;
    try {
        data_ = new T[n];
        read_data(data_, n);
        delete [] tmp;
    } catch(...) {
        delete [] data_; data_ = tmp;
        throw;     //正しくはこう。
    }
}
例外安全なコードを書くには

●
    単一の関数にatomicでない複数の処理が
    あると、例外安全の強い保証をするのは
    不可能。
●
    例)std::coutに出力してからstd::cerr
    に出力
4.例外安全にするための技法
これまでのことは
いまから紹介する
2つのテクニックの
布石に過ぎなかった
布石に過ぎなかった
      \ばばーん/
例外安全にするための技法

●
    いままで説明してきたことを上手く実装
    するためのテクニック
例外安全にするための技法

●
    いままで説明してきたことを上手く実装
    するためのテクニック
●
    Swap
例外安全にするための技法

●
    いままで説明してきたことを上手く実装
    するためのテクニック
●
    Swap
●
    RAII(Resource Acquisition Is
    Initialization)
例外安全にするための技法

           ●
               Swap
●
    実体を他に作って、全て成功した
    ら、変更したいリソースとSwapする
例外安全にするための技法

           ●
               Swap
●
    実体を他に作って、全て成功した
    ら、変更したいリソースとSwapする
●
    Swapは、例外を投げない保証を必ず
    守る
例外安全にするための技法
template<typename T>
void swap(T &lhs, T &rhs)
{
    T tmp = lhs;
    lhs = rhs;
    rhs = tmp;
}
例外安全にするための技法
void SampleClass::ReadData(int n)
{
    T *tmp = data_; data_ = 0;
    try {
        data_ = new T[n];
        read_data(data_, n);
        delete [] tmp;
    } catch(...) {
        delete [] data_; data_ = tmp;
        throw;
    } //頑張って強い例外安全にしてるけど
}
例外安全にするための技法
void SampleClass::ReadData(int n)
{
    T *tmp = data_; data_ = 0;
    try {
        data_ = new T[n];
        read_data(data_, n);
        delete [] tmp;
    } catch(...) {
        delete [] data_; data_ = tmp;
        throw;
    } //ロールバック用にいろいろ書いてて
}
例外安全にするための技法
void SampleClass::ReadData(int n)
{
    T *tmp = data_; data_ = 0;
    try {
        data_ = new T[n];
        read_data(data_, n);
        delete [] tmp;
    } catch(...) {
        delete [] data_; data_ = tmp;
        throw;
    } //例外を投げる部分が
}
例外安全にするための技法
void SampleClass::ReadData(int n)
{
    T *tmp = data_; data_ = 0;
    try {
        data_ = new T[n];
        read_data(data_, n);
        delete [] tmp;
    } catch(...) {
        delete [] data_; data_ = tmp;
        throw;
    } //例外を投げない部分に囲まれて
}
例外安全にするための技法
void SampleClass::ReadData(int n)
{
    T *tmp = data_; data_ = 0;
    try {
        data_ = new T[n];
        read_data(data_, n);
        delete [] tmp;
    } catch(...) {
        delete [] data_; data_ = tmp;
        throw;
    } //Try-Catchも入り乱れて
}
例外安全にするための技法
void SampleClass::ReadData(int n)
{
    T *tmp = data_; data_ = 0;
    try {
        data_ = new T[n];
        read_data(data_, n);
        delete [] tmp;
    } catch(...) {
        delete [] data_; data_ = tmp;
        throw;
    } //ちょっと複雑・・・
}
例外安全なコードを書くには

●
    それぞれの関数で例外を投げうる部分と
    投げない部分を明確に分離する。
●
    本来の処理の成功を確認した時点で、例
    外を投げない部分を使って、状態の変更
    と後処理を行うようにする。
例外安全にするための技法

           ●
               Swap
●
    実体を他に作って、全て成功した
    ら、変更したいリソースとSwap
例外安全にするための技法

            ●
                Swap
●
    実体を他に作って、全て成功した
    ら、変更したいリソースとSwap


例外を投げうる部分
                       投げない部分
例外安全にするための技法
void SampleClass::ReadData(int n)
{
    T *tmp = new T[n];     //先に確保
    try {
        read_data(tmp, n);//そいつで処理
    } catch(...) {
        delete [] tmp;
    }

    std::swap(data_, tmp);//終わったら入れ替え
    delete [] tmp;        //後処理
}
例外安全にするための技法

             ●
                 Swap
●
    例外を投げうる部分と投げない部分を明
    確に分離
●
    例外を投げる部分が成功したら例外を投
    げない部分で状態を変更
●
    ロールバック用のTry-Catchは要らなく
    なる!
例外安全にするための技法

             ●
                 Swap
●
    例外を投げうる部分と投げない部分を明
    確に分離
●
    例外を投げる部分が成功したら例外を投
    げない部分で状態を変更
●
    ロールバック用のTry-Catchは要らなく
    なる!
    (リソース管理用のは必要・・・)
例外安全にするための技法

              ●
                  Swap
●
    自作クラスでも、
    Copy-Constructableなクラスなら
    swapを実装する。
例外安全にするための技法
void SampleClass::swap(SampleClass &rhs)
{
    //標準のswap関数や
    std::swap(data_, rhs.data_);
    //それ用のswap関数などで
    other_data_.swap(rhs.other_data_);
}
例外安全にするための技法

                  ●
                      Swap
●
    自作クラスでも、
    Copy-Constructableなクラスなら
    swapを実装する。
●
    SampleClass
        (SampleClass const &rhs);
例外安全にするための技法

              ●
                  Swap
●
    自作クラスでも、
    Copy-Constructableなクラスなら
    swapを実装する。
●
    実装すると・・・
例外安全にするための技法

                    ●
                        Swap
●
    自作クラスでも、
    Copy-Constructableなクラスなら
    swapを実装する。
●
    Assignableなクラスに出来る。
●
    SampleClass &
      operator=(SampleClass const &)
例外安全にするための技法
SampleClass &
    SampleClass::operator=
        (SampleClass const &rhs)
{
    //コピーコンストラクタ
    SampleClass tmp(rhs);
    //swap
    tmp.swap(*this);
    return *this;
}
例外安全にするための技法
SampleClass &
    SampleClass::operator=
        (SampleClass const &rhs)
{
    //コピーコンストラクタ
    SampleClass tmp(rhs);
    //swap
    tmp.swap(*this);      さらにまとめて
    return *this;         書くと
}
例外安全にするための技法
SampleClass &
    SampleClass::operator=
        (SampleClass const &rhs)
{
    SampleClass(rhs).swap(*this);
    return *this;
}
例外安全にするための技法
SampleClass &
    SampleClass::operator=
        (SampleClass const &rhs)
{
    SampleClass(rhs).swap(*this);
    return *this;
}
 メンバ変数がAssignableであることを
 要求しない
例外安全にするための技法
SampleClass &
    SampleClass::operator=
        (SampleClass const &rhs)
{
    SampleClass(rhs).swap(*this);
    return *this;
}
             Copy And Swap
例外安全にするための技法

          ●
              RAII
●
    「リソースの確保は初期化である」
例外安全にするための技法
void SampleClass::ReadData(int n)
{
    T *tmp = data_; data_ = 0;
    try {
        data_ = new T[n];
        read_data(data_, n);
        delete [] tmp;
    } catch(...) {
        delete [] data_; data_ = tmp;
        throw;
    } //リソース管理のためにコードが複雑に
}
例外安全にするための技法
void SampleClass::ReadData(int n)
{
    T *tmp = data_; data_ = 0;
    try {
        data_ = new T[n];
        read_data(data_, n);
        delete [] tmp;
    } catch(...) {
        delete [] data_; data_ = tmp;
        throw;
    } //deleteも分散してしまった
}
例外安全にするための技法
void SampleClass::ReadData(int n)
{
    T *tmp = data_; data_ = 0;
    try {
        data_ = new T[n];
        read_data(data_, n);
        delete [] tmp;
    } catch(...) {
        delete [] data_; data_ = tmp;
        throw;
    } //対応していない
}
例外安全にするための技法

          ●
              RAII
●
    「リソースの確保は初期化である」
●
    コンストラクタでリソースを確保
●
    デストラクタでリソースを破棄
例外安全にするための技法

          ●
              RAII
●
    「リソースの確保は初期化である」
●
    コンストラクタでリソースを確保
●
    デストラクタでリソースを破棄

        対応!!
例外安全にするための技法

                    ●
                        RAII
class RAIIClass
{
    RAIIClass(Resource r) : r_(r) {}
    RAIIClass(Args as) : r_(CreateResource(as))
    {}

    ~RAIIClass() { DisposeResource(r_); }
private:
    Resource r_;
};
例外安全にするための技法

          ●
              RAII
●
    これをメモリ管理に使ったのがいわ
    ゆるスマートポインタ
例外安全にするための技法

          ●
              RAII
●
    これをメモリ管理に使ったのがいわ
    ゆるスマートポインタ
●
    プログラマはリソース解放のめんど
    くささから解放される!
例外安全にするための技法

          ●
              RAII
●
    これをメモリ管理に使ったのがいわ
    ゆるスマートポインタ
●
    プログラマはリソース解放のめんど
    くささから解放される!
●
    例外安全とか考えなくても使うべ
    き!
例外安全にするための技法

          ●
              RAII
●
    これがどのように例外安全性の点で
    重宝されるのか?
例外安全にするための技法
void SampleClass::ReadData(int n)
{
    T *tmp = data_; data_ = 0;
    try {
        data_ = new T[n];
        read_data(data_, n);
        delete [] tmp;
    } catch(...) {
        delete [] data_; data_ = tmp;
        throw;
    }
}
例外安全にするための技法

            ●
                RAII
●
    Deleteのために例外をCatchしなく
    ちゃいけなかった
例外安全にするための技法

            ●
                RAII
●
    Deleteのために例外をCatchしなく
    ちゃいけなかった
●
    でもRAIIなクラスを使うと、Delete
    は自動化できる
例外安全にするための技法
void SampleClass::ReadData(int n)
{
    T *tmp = data_; data_ = 0;
    try {
        data_ = new T[n];      これが
        read_data(data_, n);
        delete [] tmp;
    } catch(...) {
        delete [] data_; data_ = tmp;
        throw;
    }
}
例外安全にするための技法
void SampleClass::ReadData(int n)
{
    shared_array<T> tmp = data_;
    try {
        data_.reset(new T[n]); こうなる
        read_data(data_, n);
    } catch (...) {
        data_ = tmp;
    }
}
例外安全にするための技法

            ●
                RAII
●
    どこで起きるかわからないような例
    外によって関数を抜けるときも、そ
    の時に自動でリソースが解放され
    る!
●
    リソース解放のためのTry-Catchは要
    らなくなる!
例外安全にするための技法

            ●
                RAII
●
    どこで起きるかわからないような例
    外によって関数を抜けるときも、そ
    の時に自動でリソースが解放され
    る!
●
    リソース解放のためのTry-Catchは要
    らなくなる!(強い例外安全保証の
    ためのは必要・・・)
例外安全にするための技法

   ●
       SwapとRAII
例外安全にするための技法

      ●
          SwapとRAII
1.Swapはロールバック用のTry-
 Catchを不要にする。
例外安全にするための技法

      ●
          SwapとRAII
1.Swapはロールバック用のTry-
 Catchを不要にする。
2.RAIIはリソース管理用のTry-
 Catchを不要にする。
例外安全にするための技法

      ●
          SwapとRAII
1.Swapはロールバック用のTry-
 Catchを不要にする。
2.RAIIはリソース管理用のTry-
 Catchを不要にする。
3.例外中立のために、例外が起き
 てもいじらないで伝える。
例外安全にするための技法

   ●
       SwapとRAII



 合体
例外安全にするための技法
void SampleClass::ReadData(int n)
{
    shared_array<T> tmp(new T[n]);
    read_data(tmp_, n);
    std::swap(data_, tmp);
}
例外安全にするための技法
void SampleClass::ReadData(int n)
{
    shared_array<T> tmp(new T[n]);
    read_data(tmp_, n);
    std::swap(data_, tmp);
}

      おわかりいただけただろうか
例外安全にするための技法
void SampleClass::ReadData(int n)
{
    shared_array<T> tmp(new T[n]);
    read_data(tmp_, n);
    std::swap(data_, tmp);
}

      おわかりいただけただろうか
      ではもう一度・・・
例外安全にするための技法
void SampleClass::ReadData(int n)
{
    T *tmp = data_; data_ = 0;
    try {
        data_ = new T[n];
        read_data(data_, n);
        delete [] tmp;
    } catch(...) {
        delete [] data_; data_ = tmp;
    }
}
例外安全にするための技法
void SampleClass::ReadData(int n)
{
    shared_array<T> tmp(new T[n]);
    read_data(tmp_, n);
    std::swap(data_, tmp);
}
例外安全にするための技法

         ●
             SwapとRAII
●
    適切なコードを書けば、例外安全
    性のためにTry-Catchを書く必要
    はない。
例外安全にするための技法

 ●
     デストラクタで例外
例外安全にするための技法

      ●
          デストラクタで例外
●
    禁止!
例外安全にするための技法

      ●
          デストラクタで例外
●
    禁止!
●
    配列を安全にできない
●
    例外が起きたときにスタックの巻
    き戻しを安全にできない
●
    全ての例外安全の努力が水の泡!
5.まとめ
まとめ

●
    例外安全なコードを書くには
まとめ

●
    例外安全なコードを書くには
●
    例外を投げる部分と投げない部分を
    分離して、例外のある処理の成功を
    確認してから、状態を変更する。
●
    RAIIを使用してリソースの管理を自
    動化する
まとめ

●
    今回の内容はほとんど全て
    「Exceptional C++」
    (ハーブ・サッター著)
    に書かれています
●
    あと「C++ Coding Standard」も
おしまい。

More Related Content

What's hot

冬のLock free祭り safe
冬のLock free祭り safe冬のLock free祭り safe
冬のLock free祭り safe
Kumazaki Hiroki
 
Javaセキュアコーディングセミナー東京第2回演習の解説
Javaセキュアコーディングセミナー東京第2回演習の解説Javaセキュアコーディングセミナー東京第2回演習の解説
Javaセキュアコーディングセミナー東京第2回演習の解説
JPCERT Coordination Center
 
Secure scheme script suite
Secure scheme script suiteSecure scheme script suite
Secure scheme script suite
Tod Morita
 
20130611 java concurrencyinpracticech7
20130611 java concurrencyinpracticech720130611 java concurrencyinpracticech7
20130611 java concurrencyinpracticech7
Toshiaki Toyama
 

What's hot (15)

Sharing Deep Dive
Sharing Deep DiveSharing Deep Dive
Sharing Deep Dive
 
Synthesijer and Synthesijer.Scala in HLS-friends 201512
Synthesijer and Synthesijer.Scala in HLS-friends 201512Synthesijer and Synthesijer.Scala in HLS-friends 201512
Synthesijer and Synthesijer.Scala in HLS-friends 201512
 
Intel AVX2を使用したailia sdkの最適化
Intel AVX2を使用したailia sdkの最適化Intel AVX2を使用したailia sdkの最適化
Intel AVX2を使用したailia sdkの最適化
 
冬のLock free祭り safe
冬のLock free祭り safe冬のLock free祭り safe
冬のLock free祭り safe
 
Slide
SlideSlide
Slide
 
Javaセキュアコーディングセミナー東京第2回演習の解説
Javaセキュアコーディングセミナー東京第2回演習の解説Javaセキュアコーディングセミナー東京第2回演習の解説
Javaセキュアコーディングセミナー東京第2回演習の解説
 
Visual C++コード分析を支えるSAL
Visual C++コード分析を支えるSALVisual C++コード分析を支えるSAL
Visual C++コード分析を支えるSAL
 
20180123 power shell
20180123 power shell20180123 power shell
20180123 power shell
 
Secure scheme script suite
Secure scheme script suiteSecure scheme script suite
Secure scheme script suite
 
【C++BUILDER STARTER チュートリアルシリーズ】シーズン2 C++Builderの部 第1回 ‟シューティングゲームのプログラム„
【C++BUILDER STARTER チュートリアルシリーズ】シーズン2 C++Builderの部 第1回 ‟シューティングゲームのプログラム„【C++BUILDER STARTER チュートリアルシリーズ】シーズン2 C++Builderの部 第1回 ‟シューティングゲームのプログラム„
【C++BUILDER STARTER チュートリアルシリーズ】シーズン2 C++Builderの部 第1回 ‟シューティングゲームのプログラム„
 
20130611 java concurrencyinpracticech7
20130611 java concurrencyinpracticech720130611 java concurrencyinpracticech7
20130611 java concurrencyinpracticech7
 
Javaコーディング勉強会
Javaコーディング勉強会Javaコーディング勉強会
Javaコーディング勉強会
 
セキュアPHP
セキュアPHPセキュアPHP
セキュアPHP
 
signal の話 或いは Zend Signals とは何か
signal の話 或いは Zend Signals とは何かsignal の話 或いは Zend Signals とは何か
signal の話 或いは Zend Signals とは何か
 
4章 Linuxカーネル - 割り込み・例外 4
 4章 Linuxカーネル - 割り込み・例外 4 4章 Linuxカーネル - 割り込み・例外 4
4章 Linuxカーネル - 割り込み・例外 4
 

Similar to Sapporocpp#2 exception-primer

知って得するC#
知って得するC#知って得するC#
知って得するC#
Shota Baba
 
あんなテスト、こんなテスト(this and that about testing)
あんなテスト、こんなテスト(this and that about testing)あんなテスト、こんなテスト(this and that about testing)
あんなテスト、こんなテスト(this and that about testing)
Takuya Tsuchida
 
Infer.netによるldaの実装
Infer.netによるldaの実装Infer.netによるldaの実装
Infer.netによるldaの実装
池田 直哉
 
フリーでできるセキュリティWeb編(SQLMあpを楽しもう)
フリーでできるセキュリティWeb編(SQLMあpを楽しもう)フリーでできるセキュリティWeb編(SQLMあpを楽しもう)
フリーでできるセキュリティWeb編(SQLMあpを楽しもう)
abend_cve_9999_0001
 
[CB19] アンチウイルスをオラクルとしたWindows Defenderに対する新しい攻撃手法 by 市川遼
[CB19] アンチウイルスをオラクルとしたWindows Defenderに対する新しい攻撃手法 by 市川遼 [CB19] アンチウイルスをオラクルとしたWindows Defenderに対する新しい攻撃手法 by 市川遼
[CB19] アンチウイルスをオラクルとしたWindows Defenderに対する新しい攻撃手法 by 市川遼
CODE BLUE
 

Similar to Sapporocpp#2 exception-primer (12)

APASEC 2013 - ROP/JIT を使わずに DEP/ASLR を回避する手法を見てみた。
APASEC 2013 - ROP/JIT を使わずに DEP/ASLR を回避する手法を見てみた。APASEC 2013 - ROP/JIT を使わずに DEP/ASLR を回避する手法を見てみた。
APASEC 2013 - ROP/JIT を使わずに DEP/ASLR を回避する手法を見てみた。
 
今日からできる!簡単 .NET 高速化 Tips
今日からできる!簡単 .NET 高速化 Tips今日からできる!簡単 .NET 高速化 Tips
今日からできる!簡単 .NET 高速化 Tips
 
C++ マルチスレッドプログラミング
C++ マルチスレッドプログラミングC++ マルチスレッドプログラミング
C++ マルチスレッドプログラミング
 
知って得するC#
知って得するC#知って得するC#
知って得するC#
 
Inside FastEnum
Inside FastEnumInside FastEnum
Inside FastEnum
 
SpectreBustersあるいはLinuxにおけるSpectre対策
SpectreBustersあるいはLinuxにおけるSpectre対策SpectreBustersあるいはLinuxにおけるSpectre対策
SpectreBustersあるいはLinuxにおけるSpectre対策
 
あんなテスト、こんなテスト(this and that about testing)
あんなテスト、こんなテスト(this and that about testing)あんなテスト、こんなテスト(this and that about testing)
あんなテスト、こんなテスト(this and that about testing)
 
No.2 超初心者向け セキュリティ入門
No.2 超初心者向け セキュリティ入門No.2 超初心者向け セキュリティ入門
No.2 超初心者向け セキュリティ入門
 
Infer.netによるldaの実装
Infer.netによるldaの実装Infer.netによるldaの実装
Infer.netによるldaの実装
 
フリーでできるセキュリティWeb編(SQLMあpを楽しもう)
フリーでできるセキュリティWeb編(SQLMあpを楽しもう)フリーでできるセキュリティWeb編(SQLMあpを楽しもう)
フリーでできるセキュリティWeb編(SQLMあpを楽しもう)
 
[CB19] アンチウイルスをオラクルとしたWindows Defenderに対する新しい攻撃手法 by 市川遼
[CB19] アンチウイルスをオラクルとしたWindows Defenderに対する新しい攻撃手法 by 市川遼 [CB19] アンチウイルスをオラクルとしたWindows Defenderに対する新しい攻撃手法 by 市川遼
[CB19] アンチウイルスをオラクルとしたWindows Defenderに対する新しい攻撃手法 by 市川遼
 
非同期処理の基礎
非同期処理の基礎非同期処理の基礎
非同期処理の基礎
 

More from Kohsuke Yuasa (9)

オーディオ用レベルメータを作ってみよう
オーディオ用レベルメータを作ってみようオーディオ用レベルメータを作ってみよう
オーディオ用レベルメータを作ってみよう
 
Juceで作るオーディオアプリケーション
Juceで作るオーディオアプリケーションJuceで作るオーディオアプリケーション
Juceで作るオーディオアプリケーション
 
最近のC++ @ Sapporo.cpp #5
最近のC++ @ Sapporo.cpp #5最近のC++ @ Sapporo.cpp #5
最近のC++ @ Sapporo.cpp #5
 
規格書で読むC++11のスレッド
規格書で読むC++11のスレッド規格書で読むC++11のスレッド
規格書で読むC++11のスレッド
 
C++ ポインタ ブートキャンプ
C++ ポインタ ブートキャンプC++ ポインタ ブートキャンプ
C++ ポインタ ブートキャンプ
 
Introduction to boost test
Introduction to boost testIntroduction to boost test
Introduction to boost test
 
C++ template-primer
C++ template-primerC++ template-primer
C++ template-primer
 
Read egg oven
Read egg ovenRead egg oven
Read egg oven
 
Study3 boost
Study3 boostStudy3 boost
Study3 boost
 

Sapporocpp#2 exception-primer