私の大学では、C ++での実用的なプログラミングテストがあります。問題のタスクが有効であり、正しく完了することが可能であるかどうかについて確信が持てない例にとらわれています。
(単純な)タスク:
のデストラクタを完了し
Person
て、割り当てられたname
ものが再び解放されるようにします//???
main関数で、以前に割り当てられたメモリを解放するために必要なステートメントに置き換えます
最初は、タスクは私にとっては些細なことのように見えました。デストラクタの場合は、単に記述delete[] name
し、main関数で。を使用しますdelete[] friends
。おそらく、それはこの例の作者が私たちに意図したことでもあります。
でも:
このコード例には欠陥があるようです。これにより、メモリリークが発生し、デストラクタが複数回呼び出されます。
personクラスには割り当てがありません。つまり、main関数の配列のスロットに割り当てられているoperator =
などの既存のPersonオブジェクトは、内部で割り当てられたsがコピーされません。したがって、2つのオブジェクトが同じ内部ポインタを共有するようになりました。さらに、前述のアレイスロットに以前存在していた名前へのポインタが永久に失われ、避けられないメモリリークが発生します。maria
friends
name
char*
Person
呼び出されるとdelete[] friends;
、配列内のオブジェクトが破棄され、デストラクタが呼び出されてname
メンバーが解放されます。ただし、プログラムが終了すると、スコープ内のローカルのPersonオブジェクトmain
が破棄されます。もちろん、そのname
メンバーは、以前に解放されたメモリをポイントしています。
実際の質問:
- このテスト例には欠陥がありますか、それとも何かが足りませんか?
- 与えられたタスクの実行に完全に固執する場合(デストラクタの実装のみを変更し、メイン関数のコメント部分に新しいコードを挿入する)、上記の問題を修正できますか?
..
#include <iostream>
using namespace std;
int strlen(const char *str) {
if (str==0) return 0;
int i=0;
for (; str[i]; ++i);
return i;
}
void strcpy(const char *src, char *dest) {
if (src==0 || dest==0) return;
int i=0;
for (; src[i]; ++i) dest[i]=src[i];
dest[i]=’\0’;
}
class Person {
char *name;
public:
Person(const char *str = "Susi") {
name = new char[strlen(str)+1];
strcpy(str,name);
}
Person(const Person &p) {
name = new char[strlen(p.name)+1];
strcpy(p.name,name);
}
~Person() {
//...
}
void change() {
name[4]='e';
}
ostream &print(ostream &o) const {
o<<name;
return o;
}
};
int main() {
Person maria("Maria"), peter("Peter"), franz("Franz"), luisa("Luisa");
Person mary(maria);
Person luise;
Person p(luise);
Person *friends= new Person[7];
friends[0]=maria;
friends[1]=peter;
friends[2]=franz;
friends[3]=luisa;
friends[4]=mary;
friends[5]=luise;
friends[6]=p;
friends[5]=luisa;
friends[3].change();
friends[4].change();
for (int i=0; i<7; ++i) {
friends[i].print(cout);
cout<<endl;
}
//???
return 0;
}