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
    数组中的对象分配的内存,并双重删除由auto
    Person
    对象分配的内存

  • 对于每一个新项目,都应该有一个删除[].

    你是对的。违反了。@MooingDuck:你的修复程序也是不安全的——它只会吞噬任何类型的异常。正确的异常安全方法是使用
    std::vector
    std::string
    保存字符串数据。@BenVoight:是的,我忘记了catch块末尾的
    抛出;
    。你是r没错,我会使用一个
    std::string
    ,但这需要更多实质性的更改。@MooingDuck:是的,而且现有的构造函数也不是例外安全的。需要更具侵入性的更改,所以我选择只留下一条注释,说明可能性。对于每个
    新的
    a
    删除
    ,以及每个
    新的[]
    a
    delete[]
        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;