【c++primer】第12章クラスと動的メモリ割り当て


一、概念
1)静的記憶方式:プログラムの実行中に一定の記憶空間を割り当てる方式.外部変数と静的変数はこのストレージ方式に属する
2)静的メンバー変数:クラスのすべてのインスタンスに共有されます.つまり、クラスのインスタンスが静的メンバー変数を変更した場合、その変更値はクラスの他のすべてのインスタンスに表示されます.どのオブジェクトを作成しても、プログラムは静的変数のコピーを1つだけ作成します.
3)静的メンバーの特徴:静的メンバーはメモリに存在し、非静的メンバーはメモリを割り当てるためにインスタンス化する必要があるため、静的メンバーは非静的メンバーにアクセスできない.静的メンバーはメモリに存在するため、非静的メンバーはクラス内の静的メンバーに直接アクセスできます.
4)クラス宣言で静的メンバー変数を初期化することはできません.宣言にはメモリの割り当て方法が記載されていますが、メモリは割り当てられていません.
5)delete/new new char[]/delete[]ペア出現
6)newオブジェクトを作成した後、deleteでオブジェクトを削除すると、オブジェクト自体が消費するメモリを解放できます.ただし、オブジェクトメンバーに属するポインタが指すメモリは自動的に解放されません.
        
#include <iostream>
#include <cstring>
using namespace std;
class StringBad
{
private:
    char *str;
    int len;
    static int num_strings;
public:
    StringBad(const char *s);
    StringBad();
    ~StringBad();
    friend ostream &operator<< (ostream &os,const StringBad &st);
};
StringBad::StringBad(const char* s)
{
    len=strlen(s);
    str=new char[len+1];
    strcpy(str,s);
    num_strings++;
    cout<<num_strings<<":\""<<str<<"\""<<"object created
"; } StringBad::StringBad() { len=4; str=new char[4]; strcpy(str,"C++"); num_strings++; cout<<num_strings<<":\""<<str<<"\""<<"object created
"; } StringBad::~StringBad() { --num_strings; cout<<"\""<<str<<"\""<<"object deleted
"; cout<<num_strings<<"left
"; delete [] str; } ostream & operator<< (ostream &os,const StringBad &st)//must add const { os<<st.str; return os; } int StringBad::num_strings=0; void callme(StringBad &);// void callme(StringBad &rab) { cout<<"string passed by reference:"; cout<<"\""<<rab<<"\"
"; } int main() { StringBad headline1("tianshuai"); StringBad headline2("is a good student"); StringBad sports("he do good job"); cout<<"headline1:"<<headline1<<endl; cout<<"headline2:"<<headline2<<endl; cout<<"sports:"<<sports<<endl; callme(headline1); return 0; }

出力:
1:"tianshuai"object created
2:"is a good student"object created
3:"he do good job"object created
headline1:tianshuai
headline2:is a good student
sports:he do good job
string passed by reference:"tianshuai"
"he do good job"object deleted
2left
"is a good student"object deleted
1left
"tianshuai"object deleted
0left
二、構造関数
1)デフォルトコンストラクション関数:定義コンストラクション関数、すなわちパラメータなしコンストラクション関数を表示します.パラメータコンストラクション関数がある場合、すべてのパラメータにデフォルト値があります.
2)コンストラクション関数のコピー:ユーザーが独自のレプリケーションコンストラクション関数を定義していない場合、デフォルトのレプリケーションコンストラクション関数が生成されます.値でオブジェクトを渡すと、シェイプパラメータの一時オブジェクトが作成され、レプリケーションコンストラクタを呼び出して一時オブジェクトの値を実パラメータにレプリケーションします.
機能:オブジェクトの非静的メンバーの値を別のオブジェクトに個別にコピーします.メンバーの値がコピーされていることに注意してください.このコピーは浅いコピーとも呼ばれます.静的メンバーはクラス全体に属し、オブジェクトに属しないため、レプリケーションコンストラクション関数を呼び出すと静的メンバーは影響を受けません.
≪いつ使用|Use|oem_src≫:オブジェクトを値で渡し、関数はオブジェクトを返し、あるオブジェクトで別のオブジェクトを初期化します.つまり、レプリケーション初期化時に、要素初期化リストに基づいて配列要素を初期化します.この4つの場合、レプリケーションコンストラクション関数が呼び出されます.レプリケーションコンストラクション関数は初期化にのみ使用でき、値の割り当てには使用できません.値の割り当て時にレプリケーションコンストラクション関数を呼び出すのではなく、値の割り当てオペレータを使用します.
3)複製構造関数の解析:s 1=s 2;
                                              s1.str=s2.str;//ここでs 1は文字列ではなく文字列を指すポインタをコピーする
                                              s1.len=s2.len;
s 2の解析関数が呼び出されるとstrが指すメモリdelete[]s 2が解放される.str.s 1に問題が発生する
解決策:深度コピー
             StringBad::StringBad(const StringBad &st)
             {
                   len=st.len;
                   str=new char[len +1 ];//キーnew動的申請を使用して文字列を格納するメモリ
                   strcpy(str,st.str)
             }                    
4)割り当てとレプリケーション初期化の違いを理解する(ポイント):割り当ては、2つの既存のオブジェクト間で行われます.つまり、1つの既存のオブジェクトで別の既存のオブジェクトの値を変更します.割り当てオペレータは、割り当てオペレータを呼び出してオブジェクトを操作し、割り当てオペレータはオペレータの再ロードで説明します.例えばhyong、文hyong x(1);hyong y(1,2)はx=yである.これは、オブジェクトxとyがすでに存在するオブジェクトであり、文hyong x=yであるため、付与値である.レプリケーション初期化は、既存のオブジェクトyで新しいオブジェクトxを作成するので、レプリケーション初期化です.
三、stringの改善
       1)strcmp(const char *s1,const char * s2)
s 1s 2の場合、戻り値>0
2)静的メソッド:静的メソッドは、静的変数と同様に、そのクラスのオブジェクトではなくクラス自体に属します.staticとして定義されたメソッドを呼び出すには、その前にクラスの名前を付ける必要があります.
使用規則:静的メソッドはクラスの静的メンバーにのみアクセスでき、クラスの非静的メンバーにはアクセスできません.
非静的メソッドは、クラスの静的メンバーにアクセスしたり、クラスの非静的メンバーにアクセスしたりすることができます.
静的メソッドはインスタンスを使用して呼び出すことはできません.クラス名のみを使用して呼び出すことができます.
3)newオペレータのレイアウト:メモリの割り当て時に既存のメモリの場所を指定します.既知の配列で適切なサイズの領域を再申請する
            char   *buffer=new char[512];
            p1 = new (buffer)JustTesting;
            p2 = new (buffer + sizeof(JustTesting))JustTesting("tian",5);
            delete [ ] buffer;p 1,p 2解析関数を呼び出さない
            delete p1; p 1ではなくbufferを解放する
            p1->~JustTesting();