効果的なC ++項目29:(「異常セキュリティ」としてではなく、価値がある努力)を実現

まず、プレゼンテーションは、例例外をスローすることがあります

  • ここで混入背景画像を相互に排他的として並行性制御を有する単一のGUIメニューを表すために使用されるクラスは、次のとおりです。
void lock(Mutex* pm);   //锁定pm所指的互斥器
void unlock(Mutex* pm); //将互斥器解锁

class PrettyMenu {
public:
    void changeBackground(std::istream& imgSrc) {
        lock(&mutex);   //取得互斥器
        delete bgImage; //删除旧图片
        ++imageChanges; //修改图像更改次数
        bgImage = new Image(imgSrc); //安装新的背景图片
        unlock(&mutex); //释放互斥器
    }
private:
    Mutex mutex;     //互斥器
    Image* bgImage;  //目前使用的背景图片
    int imageChanges;//图片被修改的次数
};
  • changeBackground上記()メンバ関数は、「異常安全」ではありません 例外安全機能は、次の2つの特徴を持っている必要があるため。
    • ①任意のリソース開示しない:新しいイメージ()操作は、例外が発生した場合、その後のロック解除を呼び出すことはありません、上記のコードを、そのmutexは永久にロックされます。メンバ関数があることを保証するものではありませんので、
    • ②データの破壊を許可しない:新しいイメージ()オペレーションが例外が発生した場合、bgImageは削除されている、とリソースが変更されているので、数のimageChangesも、蓄積すること。ただし、この機能があることを保証するものではありません。

第二に、問題解決のためのリソースリーク

  • この問題は、オブジェクトがリソースを管理する方法について説明を簡単に解決され、第14条はまた、第13条で次のようにmutexを管理するために、ロックという名前のクラス独自のデザインが定義されている導入しました:
//初始化对象时锁住互斥器,对象释放时自动解除互斥器
class Lock
{
public:
    //获得资源
    explicit Lock(Mutex* pm) :mutexPtr(pm) {
        lock(mutexPtr);
    }
 
    //释放资源
    ~Lock() { unlock(mutexPtr); }
private:
    Mutex *mutexPtr;
};

//重写修改PrettyMenu的成员函数
void PrettyMenu::changeBackground(std::istream& imgSrc) {
    Lock ml(&mutex);//将互斥器封装在类中进行管理
    delete bgImage; //删除旧图片
    ++imageChanges; //修改图像更改次数
    bgImage = new Image(imgSrc); //安装新的背景图片
}
  • 上記の初期化ミューテックスは、私たちのライフサイクル終了オブジェクトを手動でミューテックスを解放する必要がない場合、ロックされ、ミューテックスオブジェクトクラスにカプセル化され、デストラクタは自動的にように、ミューテックスが解放された私たちを助けますメソッドは、リソースリークの問題を解決することができます

第三に、データの破損の問題を解決するために

  • 上記は、リソース・リークの一般解を説明し、現在はデータ破壊の問題を見て。これに先立ち、我々は最初のいくつかの用語を定義します。
    • ①基本的な約束:例外がスローされた場合、プログラム内のすべてがアクティブ状態のままにしてください
    • ②強い保証:プログラムが例外をスローした場合、プログラムの状態を保証するべきではありません。;関数が失敗した場合、プログラムは国家の「関数を呼び出す前に」に戻ります機能が正常に正常に完了している場合:保証すべきであるような関数を呼び出します
    • ③保証をスローしない:コミットメント例外をスローしないように、彼らは常に彼らのオリジナルのコミットメントの機能を果たすことができますので、
  • 例外セーフコードがない場合は3のいずれかが、その後のコードは、例外安全ではないことを保証するために提供されなければなりません
  • changeBackground()関数は、データが破壊されないことを保証するためには、次のコードに変更することができます。
    • 使用してImageオブジェクトを管理するスマートポインタを
    • 順序の関数で並べ替えchangeBackground()ステートメントそのような置換画像のみimageChangesを蓄積した後、
    • changeBackground()内部関数での手動で削除します古い画像への必要性、それは自動的に削除スマートポインタによって管理されているように、(内部リセットと呼ばれています)
class PrettyMenu {
//...
private:
    std::tr1::shared_ptr<Image> bgImage;
};

//重写修改PrettyMenu的成员函数
void PrettyMenu::changeBackground(std::istream& imgSrc) {
	Lock ml(&mutex);
	bgImage.reset(new Image(imgSrc));
	++imageChanges;
}

四、コピーおよびスワップ戦略

  • それはchangeBackground()関数であり、「三」はデータ破損の問題を解決するが、解決されない問題があり、コンストラクタが例外イメージを投げること
  • 原則とスワップ戦略はコピーです:あなたは、変更と体のコピーに変更を加えるために、オブジェクト(オリジナル)をコピーするつもりです。
    • 改変体のコピーが例外をスローした場合、元のオブジェクトの状態を変更することはありません
    • あなたは例外がスローされることなく、身体のコピーを変更した場合、それは元のオブジェクトの交換(スワップ)のコピーを変更されます
  • PIMPLイディオムの道:
    • 元のオブジェクトは、クラス(又は構造)の中にカプセル化されます
    • 31の用語で、PIMPLイディオムと呼ばれるこのアプローチは、説明します
  • 上記PrettyMenu、次のように記述された典型的な場合:

ケース・プレゼンテーション

  • 上記PrettyMenu、次のように記述された典型的な場合: 
//将bgImage和imageChanges从PrettyMenu独立出来,封装到一个结构中
struct PMImpl {
    std::tr1::shared_ptr<Image> bgImage;
    int imageChanges
};

class PrettyMenu {
    //...
private:
    std::tr1::shared_ptr<PMImpl> pImpl; //创建一个该结构
};
  • 今、私たちはchangeBackground()関数を修正しています。
void PrettyMenu::changeBackground(std::istream& imgSrc) {
    using std::swap; //见条款25

    Lock ml(&mutex);
	
    //以pImpl为原件,创建一个副本,然后在副本上做修改
    std::tr1::shared_ptr<PMImpl> pNew(new PMImpl(*pImpl));
    pNew->bgImage.reset(new Image(imgSrc));
    pNew->imageChanges++;

    //如果上面副本的修改没有抛出异常,那么交换副本与原件
    swap(pImpl, pNew);
}

V.の概要

  • 例外安全機能の例外は、任意のデータがリソースをリークしたり、構造的な損傷が発生することはできません。基本的な、強力なタイプ、nothrowタイプ:このような機能は、三つの可能な保証に分かれています
  • 「強力な保証は、」多くの場合、コピーとスワップまで達成することができますが、「強い保証は、」すべての機能を実現することができるために実用的な意義を持っているか、いません
  • 最も弱い関数は、通常の「異常なセキュリティの保証」と呼ばれる様々な機能の最大値に等しい「異常セキュリティ保証」を提供します
リリース1494元の記事 ウォンの賞賛1053 ビュー42万+

おすすめ

転載: blog.csdn.net/qq_41453285/article/details/104475116