Menu
Coddy logo textTech

ディープコピー

CoddyのCジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 15/61。

Cである構造体を別の構造体に代入すると、浅いコピーになります。すべてのフィールドがバイト単位でコピーされます。これは整数のような単純な値では問題なく機能しますが、ポインターでは問題が生じます。両方の構造体が同じメモリを指すことになるためです。

typedef struct {
    char *name;
    int age;
} Person;

Person alice = {"Alice", 30};
Person copy = alice;  // シャローコピー!
// alice.name と copy.name の両方が同じ文字列を指しています

一方を解放すると、もう一方は無効になります。一方を通じて文字列を変更すると、両方にその変更が反映されます。これは、望む結果になることはほとんどありません。

deep copy はポインタメンバー用に新しいメモリを割り当て、actual data を copy します:

Person *clone_person(const Person *original) {
    Person *copy = malloc(sizeof(Person));
    copy->name = malloc(strlen(original->name) + 1);
    strcpy(copy->name, original->name);
    copy->age = original->age;
    return copy;
}

これで各オブジェクトはそれぞれ独自の文字列を所有します。一方を変更したり解放したりしても、もう一方には影響しません。パターンは単純です。各ポインタメンバーについて、新しいメモリを確保し、アドレスだけでなく内容をコピーします。

challenge icon

チャレンジ

簡単

Studentモジュールを構築して、ディープコピーのパターンを示しましょう。学生オブジェクトの完全に独立したコピーを生成するcloning functionを作成します。つまり、元のオブジェクトを変更または解放しても、cloneには影響がありません。

3つのファイルを作成します。

  • student.h:2つのメンバー、char *name(dynamically allocated string)とint gradeを持つStudent structをDeclareします。3つのfunctionsをDeclareします。
    • create_student:nameとgradeを受け取り、新しいStudentへのpointerを返すconstructor
    • clone_studentconst Student *を受け取り、新しく独立したcopyへのpointerを返す
    • free_student:Allocateされたすべてのmemoryを適切に解放するdestructor
    シンボルSTUDENT_Hを使用してinclude guardsを設定します。
  • student.c:3つすべてのfunctionsをImplementします。clone_student functionが重要です。structとname stringの両方にfreshなmemoryをAllocateし、actualなstring data(pointer addressだけではありません)をcopyする必要があります。これにより、cloneはoriginalから完全に分離された独自のmemoryを所有します。
  • main.c:studentを作成し、cloneし、両方のstudentsのinformationを表示してから、両方のobjectsを適切にclean upします。

2つの入力を受け取ります:student name(string)とgrade(integer)です。

main fileで、提供されたvaluesを使ってstudentを作成し、そのstudentのcloneを作成します。originalとcloneの両方のinformationをPrintして、同じdataを含んでいることを確認します。最後に、両方のstudentsをfreeし、confirmationをPrintします。

次のFormatでoutputをPrintします。

Original: {name}, Grade: {grade}
Clone: {name}, Grade: {grade}
Both freed

たとえば、入力がAlice95の場合、outputは次のようになります。

Original: Alice, Grade: 95
Clone: Alice, Grade: 95
Both freed

ディープコピーのパターンにより、各objectが本当にindependentになります。cloneは独自にAllocateされたstringを持ち、originalのmemoryへのshared pointerではありません。

自分で試してみよう

#include <stdio.h>
#include <stdlib.h>
#include "student.h"

int main() {
    char name[100];
    int grade;
    
    // 入力を読み取る
    scanf("%s", name);
    scanf("%d", &grade);
    
    // TODO: 提供された名前と成績で学生を作成する
    
    // TODO: 学生のクローンを作成する
    
    // TODO: Print the original student's information
    // 形式: "Original: {name}, Grade: {grade}"
    
    // TODO: クローンの情報を出力する
    // 形式: "Clone: {name}, Grade: {grade}"
    
    // TODO: 両方の学生を解放する
    
    // 確認を出力する
    printf("Both freed\n");
    
    return 0;
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン

自分で練習してみよう: Cオンラインコンパイラ