ディープコピー
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;
}
これで各オブジェクトはそれぞれ独自の文字列を所有します。一方を変更したり解放したりしても、もう一方には影響しません。パターンは単純です。各ポインタメンバーについて、新しいメモリを確保し、アドレスだけでなく内容をコピーします。
チャレンジ
簡単Studentモジュールを構築して、ディープコピーのパターンを示しましょう。学生オブジェクトの完全に独立したコピーを生成するcloning functionを作成します。つまり、元のオブジェクトを変更または解放しても、cloneには影響がありません。
3つのファイルを作成します。
student.h:2つのメンバー、char *name(dynamically allocated string)とint gradeを持つStudentstructをDeclareします。3つのfunctionsをDeclareします。create_student:nameとgradeを受け取り、新しいStudentへのpointerを返すconstructorclone_student:const Student *を受け取り、新しく独立したcopyへのpointerを返すfree_student:Allocateされたすべてのmemoryを適切に解放するdestructor
STUDENT_Hを使用してinclude guardsを設定します。student.c:3つすべてのfunctionsをImplementします。clone_studentfunctionが重要です。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たとえば、入力がAliceと95の場合、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;
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
自分で練習してみよう: Cオンラインコンパイラ