Effective C++学習ノートの第4章(1)

3312 ワード

chapter 4:設計と宣言
item 18:インタフェースを正しく使用しやすくし、誤用されにくい理想的な状況では、コンパイルが通過すれば、インタフェースは必ずあなたが望んでいることを実現することができます.そうしないと、コンパイルは時間データを表すクラスの構造関数を設計していると仮定できません.Date(int month,int day,int year);これにより、パラメータの順序が間違っているのではなく、パラメータの値範囲が間違っているという2つの問題が発生します.1)ユーザがパスする際の順序が間違っている.OK、構造体を使うことを考えたかもしれませんが、暗黙的な変換は許されません.次のようになります.
struct Day{

explicit Day(int d):val(d){ }

int val;};

同様にMonthとYearに対して類似の構造体を定義することで,問題を解決できるように見える.PS:Day,Month,Yearを完全にカプセル化されたデータの中に置くのは、このように単独で構造体を定義するよりも良いです.詳しくはitem 22を参照してください.
Date d(30, 3, 1995);                      // error! wrong types

Date d(Day(30), Month(3), Year(1995));    // error! wrong types

Date d(Month(3), Day(30), Year(1995));    // okay, types are correct

2)ユーザがパラメータを送信する際のデータ範囲が間違っている.どのようにして変数があるべき値の範囲を合理的に表すことができますか.例えばここには12個のMonthしかありません.OKは、次のように定義できます.
class Month {

public:

  static Month Jan() { return Month(1); }   // functions returning all valid

  static Month Feb() { return Month(2); }   // Month values; see below for

  ...                                       // why these are functions, not objects,                    。                      

 static Month Dec() { return Month(12); }  

  ...                                       // other member functions

private:

  explicit Month(int m);                    // prevent creation of new Month values

 ...                                       // month-specific data

};

その後、Date d(Month::Mar(),Day(30),Year(1995);OKです.3)できるだけbuilt-in typesとデザインのタイプを一致させます.built-in typesとの無端な互換性を避けることは、実際には動作の一貫性を提供するインタフェースです.4)どのインタフェースも、お客様が何かをしなければならないことを覚えておく必要がある場合は、お客様がそのことを忘れてしまう可能性があるため、「正しく使用しない」傾向があります.例えばitem 13で動的に割り当てられた場合、メモリの漏洩を避けるために、メモリの解放を担当するために戻るポインタをポインタに渡します.std::tr1::shared_ptr createInvestment(); しかし、もしお客様がスマートポインタを使うのを忘れたらどうしますか.ここで良い設計原則は、人を先制し、スマートポインタに直接戻ることです.これにより、リソースの解放を忘れる可能性がほぼ完全に解消されます.5)item 14でも述べたようにtr 1::shard_ptrでは、リソース解放関数をバインドできますが、「誤ったリソース構造関数を使用しようとする」可能性があります.たとえば、deleteではなくgetRidOfInvestmentを使用したいリソース構造関数です.エラーを回避するために、getRidOfInvestmentを削除器にバインドしたtr 1::shared_を返すことができます.ptrポインタ.これでCreateInvestmentでnullのtr 1::shared_を作成しようとしましたptrはgetRidOfInvestmentを削除器として使用します.このように:std::tr 1::shared_ptr pInv(0, getRidOfInvestment); しかし、これはコンパイルできません.0はint型なので、ポインタに変換できません.変換できても、それはよくありません.ここでは強制変換を使用して実現することができる.コードは次のようになります.
std::tr1::shared_ptr<Investment> createInvestment()

{

	std::tr1::shared_ptr<Investment> pInv(static_cast<Investment*>(0),getRidOfInvestment);

	pInv= ...;//         ;

	return pInv;

}

6)もちろん、pInvによって管理された元のポインタがpInvを確立する前に決定できる場合、「元のポインタをpInvコンストラクタに渡す」は、「pInvをnullに初期化してから付与操作を行う」よりも、item 26を参照してください.7)もう一つのtr 1::shared_ptrの1つの良い性質は、「各ポインタ固有の削除器」を自動的に使用し、「cross-DLL problem」という潜在的な顧客エラーを解消することです.この問題は、「オブジェクトが1つのダイナミックリンクライブラリDLLでnewによって作成するが、別のダイナミックリンクライブラリDLLでdeleteによって破棄される」ことに起因する.多くのプラットフォームでは、このような「DLLにまたがるnew/deleteのペア運用によりruntime errorが発生します.tr 1::shared_ptrは、デフォルトの削除器が「tr 1::shared_ptr」から来ているため、この問題を回避できます.ptrが作成されたDLL"のdelete.すなわち、作成されたtr 1::shared_ptrは、「cross-DLL problem」を気にすることなく、他のDLLに渡すことができる.このtr 1::shared_ptrsは記録を追跡し、リソースの適用回数が0になると、バインドされたDLL's deleteを呼び出す.