[C++]レプリケーション作成者(5-2)


「深い放射線」と「浅い放射線」


以前に学習したレプリケーション生成者のメンバーを使用してメンバーをレプリケーションすることを「浅いレプリケーション」と呼びます.これは、メンバー変数がhipのメモリ領域を参照する場合に問題です.
では、問題点を確認しましょう.

レプリケーション作成者の問題点


次の例を見て、どの点が間違っているのか考えてみましょう.
#include <iostream>
#include <cstring>
using namespace std;

class Person
{
private:
    char*name;
    int age;
public:
    Person(char *myname, int myage)
    {
        int len= strlen(myname)+1;
        name = new char[len];
        strcpy(name, myname);
        age = myage;
    }
    void ShowPersonInfo() const
    {
        cout<<"이름 : "<<name<<endl;
        cout<<"age : "<<age<<endl;
    }
    ~Person()
    {
        delete [] name;
        cout<<"called destructor"<<endl;
    }
};

int main(void)
{
    Person man1("Lee Dong Woo",29);
    Person man2 = man1;
    man1.ShowPersonInfo();
    man2.ShowPersonInfo();
    return 0;
}

変なところ見つけたか!?
2つのオブジェクトが生成され、消滅者は1回しか呼び出されません!
どうしてこんなことになったの?
問題は浅い放射線にある.
Person man2 = man1;
上記の文に基づいてman 2を生成し、デバッガレプリケーションジェネレータを呼び出します.
でも.
Replication Creatorでは、メンバー対メンバーのみがコピーされるため、次の構造があります.

でも上と違うと.

もしあなたがそう思うならば、あなたは間違って、ほほほ
でも!
デフォルトのレプリケーション・ジェネレータでは、メンバー対メンバーの単純なレプリケーションが行われるため、レプリケーションの結果、1つの文字列が2つのオブジェクトが同時に参照されるようになります.
そのため、オブジェクトの消滅過程で問題が発生します!
まずman 2オブジェクトがまず消滅すると仮定する.
ではman 2のnameが参照する文字列は消失状態にある.
今、私たちはman 1オブジェクトの消滅を行います.
すでにnameが参照している文字列は破棄されました!
だから.
delete []name;
この文章は問題になる.
これは、削除された文字列に対して削除演算が行われるためです.
したがって、レプリケーション作成者を定義するときは、これらの問題を回避することに注意してください.

複製作成者定義


問題を解決する方法で私たちが間違っていると思っている方法を解決することができます.
各オブジェクトは文字列を参照するため、破棄中に問題は発生しません.
この形の放射線を「深放射線」と呼ぶ.
メンバーだけでなく、ポインタが参照するオブジェクトも深くコピーされます.
    Person(const Person& copy): age(copy.age)
    {
        name = new char[strlen(copy.name)+1];
        strcpy(name, copy.name); // copy name을 name에 저장, copy name은 새로운 동적할당
    }
それを加えればいいです.
擬似生成者が行う作業は以下の2つである.
  • メンバー変数ageのメンバー対メンバーコピー
  • メモリが空間を割り当てた後、文字列をコピーし、割り当てられたメモリのアドレス値をメンバー名
  • に格納する.
    したがって

    このようにコピーします.

    問題05-1[レプリケーション作成者の定義]


    NameCardクラスは、問題04-3の問題2によって定義される.ただし、このクラスは、ジェネレータ内に3つのメモリ領域が動的に割り当てられているため、ジェネレータをコピーする必要があるクラスでもあります.
    レプリケーションジェネレータを正しく定義し、次のmain関数でレプリケーション後に問題が発生しないことを確認してください.
    [main関数の例]
    int main(void)
    {
        NameCard manClerk("Lee","ABEng","010-2342-1231",COMP_POS::CLERK);
        NameCard copy1 = manClerk;
        NameCard manSENIOR("Seo","APPLE","010-2342-1231",COMP_POS::SENIOR);
        NameCard copy2 = manSENIOR;
        copy1.ShowNameCardInfo();
        copy2.ShowNameCardInfo();
        return 0;
    }

    答え

    #include <iostream>
    #include <cstring>
    
    using namespace std;
    
    namespace COMP_POS
    {
        enum {CLERK, SENIOR, ASSIST, MANAGER}; // 열거형 상수
    
        void ShowPositionInfo(int pos)
    {
            switch (pos) {
                case CLERK: //0
                    cout<<"사원"<<endl;
                    break;
                case SENIOR: // 1
                    cout<<"주임"<<endl;
                    break;
                case ASSIST: // 2
                    cout<<"대리"<<endl;
                    break;
                case MANAGER: // 3
                    cout<<"과장"<<endl;
                    break;
            }
        }
    }
    
    class NameCard
    {
    private:
        char * name; // 성명
        char * company; // 회사이름
        char * phone; // 폰번
        int position; // 직급
    public:
        NameCard(char * _name, char * _company, char * _phone, int pos):position(pos)// 생성자와 이니셜라이저
        {
            this->name = new char[strlen(_name)+1]; // 크기만큼 동적할당
            this->company = new char[strlen(_company)+1];
            this->phone = new char[strlen(_phone)+1];
            strcpy(this->name, _name);
            strcpy(this->company, _company);
            strcpy(this->phone, _phone);
        }
        NameCard(const NameCard& copy ):position(copy.position)
        {
            name = new char[strlen(copy.name)+1]; // 크기만큼 동적할당
            company = new char[strlen(copy.company)+1];
            phone = new char[strlen(copy.phone)+1];
            strcpy(name, copy.name);
            strcpy(company, copy.company);
            strcpy(phone, copy.phone);
        }
        void ShowNameCardInfo() const
        {
            cout<<"name : "<<name<<endl;
            cout<<"company : "<<company<<endl;
            cout<<"phone : "<<phone<<endl;
            cout<<"position : "<<position<<endl;
            cout<<endl;
        }
        ~NameCard() // 소멸자
        {
            delete []name;
            delete [] company;
            delete [] phone;
        }
    };
    
    //int main(void)
    //{
    //    NameCard manClerk("Lee","ABEng","010-2342-1231",COMP_POS::CLERK);
    //    NameCard manSENIOR("Seo","APPLE","010-2342-1231",COMP_POS::SENIOR);
    //    NameCard manAssist("Kim","SAMSUNG","010-2342-1231",COMP_POS::ASSIST);
    //    manClerk.ShowNameCardInfo();
    //    manSENIOR.ShowNameCardInfo();
    //    manAssist.ShowNameCardInfo();
    //    return 0;
    //}
    int main(void)
    {
        NameCard manClerk("Lee","ABEng","010-2342-1231",COMP_POS::CLERK);
        NameCard copy1 = manClerk;
        NameCard manSENIOR("Seo","APPLE","010-2342-1231",COMP_POS::SENIOR);
        NameCard copy2 = manSENIOR;
        copy1.ShowNameCardInfo();
        copy2.ShowNameCardInfo();
        return 0;
    
    
    }
    
    そのまま!
    レプリケーションジェネレータを生成すればいいです.