C+中可能存在的逻辑缺陷+;测试示例 在我的大学里,C++中有一个实用的编程测试,我遇到了一个例子,我不确定是否有问题,甚至是正确的,而且可能正确地完成。
简单任务:C+中可能存在的逻辑缺陷+;测试示例 在我的大学里,C++中有一个实用的编程测试,我遇到了一个例子,我不确定是否有问题,甚至是正确的,而且可能正确地完成。,c++,memory,memory-management,memory-leaks,C++,Memory,Memory Management,Memory Leaks,简单任务: 完成Person的析构函数,以便再次释放分配的名称 在main函数中,用释放先前分配的内存所需的语句替换/? 起初,这些任务对我来说似乎微不足道:对于析构函数,只需编写delete[]name,然后在main函数中使用delete[]friends。想必,这也是这个例子的作者想要我们做的 但是: 这个代码示例中似乎有一个缺陷,它会导致多次调用内存泄漏和析构函数 person类没有赋值operator=,这意味着当现有person对象(如maria)被分配到主函数中的friends
- 完成
的析构函数,以便再次释放分配的Person
名称
- 在main函数中,用释放先前分配的内存所需的语句替换
/?
delete[]name
,然后在main函数中使用delete[]friends
。想必,这也是这个例子的作者想要我们做的
但是:
这个代码示例中似乎有一个缺陷,它会导致多次调用内存泄漏和析构函数
person类没有赋值operator=
,这意味着当现有person对象(如maria
)被分配到主函数中的friends
数组中的插槽时,内部分配的name
不会被复制。因此,两个对象现在共享相同的内部char*
指针!此外,指向先前驻留在所述阵列插槽中的人的姓名的指针永久丢失,导致不可避免的内存泄漏
作为删除[]个好友调用代码>时-数组中的对象被销毁-导致调用它们的析构函数并释放它们的名称
成员。然而,当程序结束时,main
范围内的本地Person对象将被销毁-当然,这些对象的name
成员仍然指向以前已释放的内存
实际问题:
- 这个测试示例是否有缺陷,或者我是否遗漏了什么
- 如果完全坚持执行给定的任务(仅更改析构函数的实现,并在主函数中的注释部分插入新代码),上面列出的问题是否可以修复
#包括
使用名称空间std;
int strlen(常量字符*str){
如果(str==0)返回0;
int i=0;
for(;str[i];++i);
返回i;
}
无效strcpy(常量字符*src,字符*dest){
如果(src==0 | | dest==0)返回;
int i=0;
对于(;src[i];++i)dest[i]=src[i];
dest[i]='\0';
}
班主任{
字符*名称;
公众:
个人(const char*str=“Susi”){
name=新字符[strlen(str)+1];
strcpy(str,name);
}
人员(const Person&p){
name=新字符[strlen(p.name)+1];
strcpy(p.name,name);
}
~Person(){
//...
}
无效更改(){
名称[4]=“e”;
}
ostream&print(ostream&o)const{
o你是绝对正确的。你只需在指定的位置进行更改就可以解决问题,但是这些更改将非常极端:
将析构函数内的/…
替换为:
delete[] name;
}
Person& operator=(const Person& other)
{
if (this != &other) {
delete[] name; // not completely exception-safe!
name = new char[strlen(other.name)+1];
strcpy(other.name,name);
}
return *this;
另一个严重的问题是重新定义一个标准函数(strcpy
),使用一个新的定义对参数进行重新排序。
(另请参见:SQL注入攻击,这也会导致现有语法元素对(通常是引号和括号)与插入的语法元素重新配对)
是的,该测试示例有缺陷,可能是有意识地完成的。类Person
肯定需要赋值运算符,请记住
不,这是不可能的。默认编译器生成的赋值运算符将泄漏由friends
数组中的对象分配的内存,并双重删除由autoPerson
对象分配的内存
对于每一个新项目,都应该有一个删除[].你是对的。违反了。@MooingDuck:你的修复程序也是不安全的——它只会吞噬任何类型的异常。正确的异常安全方法是使用std::vector
或std::string
保存字符串数据。@BenVoight:是的,我忘记了catch块末尾的抛出;
。你是r没错,我会使用一个std::string
,但这需要更多实质性的更改。@MooingDuck:是的,而且现有的构造函数也不是例外安全的。需要更具侵入性的更改,所以我选择只留下一条注释,说明可能性。对于每个新的a删除,以及每个新的[]
adelete[]
。
delete[] name;
}
Person& operator=(const Person& other)
{
if (this != &other) {
delete[] name; // not completely exception-safe!
name = new char[strlen(other.name)+1];
strcpy(other.name,name);
}
return *this;