数据的双重删除不';t崩溃 我正在学习C++,编写程序来学习拷贝构造函数和运算符重载。我感到惊讶的是,当使用复制构造函数时,下面的程序并没有崩溃,而是说“Double Free”,而当使用Operator=overloading时,程序始终崩溃 #include <iostream> using namespace std; class XHandler { public: XHandler() { data = new char[8]; strcpy(data, "NoName"); } XHandler (const char *str) { data = new char (strlen(str) + 1 ); strcpy (data, str); } XHandler (const XHandler &xh) { data = xh.data; } XHandler& operator = (const XHandler &xh) { data = xh.data; } ~XHandler() { delete data; } void debug() { cout << data <<endl; } private: char *data; }; int main() { XHandler wm("hello"), wb("there"); wm.debug(); wb.debug(); XHandler wc (wm); wc.debug(); XHandler wd; wd = wc; wd.debug(); }

数据的双重删除不';t崩溃 我正在学习C++,编写程序来学习拷贝构造函数和运算符重载。我感到惊讶的是,当使用复制构造函数时,下面的程序并没有崩溃,而是说“Double Free”,而当使用Operator=overloading时,程序始终崩溃 #include <iostream> using namespace std; class XHandler { public: XHandler() { data = new char[8]; strcpy(data, "NoName"); } XHandler (const char *str) { data = new char (strlen(str) + 1 ); strcpy (data, str); } XHandler (const XHandler &xh) { data = xh.data; } XHandler& operator = (const XHandler &xh) { data = xh.data; } ~XHandler() { delete data; } void debug() { cout << data <<endl; } private: char *data; }; int main() { XHandler wm("hello"), wb("there"); wm.debug(); wb.debug(); XHandler wc (wm); wc.debug(); XHandler wd; wd = wc; wd.debug(); },c++,memory,C++,Memory,我理解双重删除是未定义的行为。但是,我想知道的是,它总是以一种方式崩溃,而以另一种方式不崩溃。您的程序有未定义的行为 问题: data = new char (strlen(str) + 1 ); 这不会分配strlen(str)+1个字符。相反,它只分配一个字符,并将strlen(str)+1值放入其中。之后执行strcpy时,缓冲区溢出(将strlen(str)-1个字符写入分配的空间)会损坏堆栈。要分配数组,应使用方括号: data = new char [strlen(str) + 1

我理解双重删除是未定义的行为。但是,我想知道的是,它总是以一种方式崩溃,而以另一种方式不崩溃。

您的程序有未定义的行为

问题:

data = new char (strlen(str) + 1 );
这不会分配
strlen(str)+1个
字符。相反,它只分配一个字符,并将
strlen(str)+1
值放入其中。之后执行strcpy时,缓冲区溢出(将strlen(str)-1个字符写入分配的空间)会损坏堆栈。要分配数组,应使用方括号:

data = new char [strlen(str) + 1 ];
第二,使用
delete[]数据删除数据。否则,您将获得未定义的行为

第三,strcpy代码不会复制字符串的空终止符。应添加空终止符:

data[ strlen(str) ] = 0;
在strcpy行之后;(见评论)

此外,不要求应用程序在双重删除时崩溃。删除同一内存两次是错误的。

未定义行为的行为只是未定义。这意味着,没有人在这些案例中投入精力,因为这些案例不应该发生。即使是工作程序也可能是“未定义的行为”

在双删除的特殊情况下,发生的情况实际上取决于分配器的实现。通常的实现是将释放的内存放入一个列表中,下一次分配将满足此列表中的一个元素。如果双重删除一块内存,它将被添加到列表中两次。然后,两个分配将满足于相同的内存块,从而在相同的内存位置创建两个对象


顺便说一句:你的析构函数已经坏了,因为它没有使用数组删除。

我编写了这段测试代码,希望它能在这里有所帮助,我认为crush与平台有很多关系,这不仅仅是偶然的,因为这段代码在linux中被压碎,但在codeblock IDE中工作良好

#include <iostream>
#include <cstring>
#include <stdio.h>
using namespace std;

class XHandler
{
    public:
    XHandler()
    {
            data = new char[8];
            strcpy(data, "NoName");
            std::cout<< "default construcor is called" << std::endl;
    }
    XHandler (const char *str)
    {
            data = new char [strlen(str) + 1 ];
            strcpy (data, str);
             std::cout<< "param construcor is called" << std::endl;

    }
    XHandler (const XHandler &xh)
    {
            data = xh.data;
            std::cout<< "copy construcor is called" << std::endl;

    }
    XHandler& operator = (const XHandler &xh)
    {
            data = xh.data;
            std::cout<< "operator construcor is called" << std::endl;

            return *this;
    }
    ~XHandler()
    {
        std::cout<< "destrucor is called" << std::endl;
        print_dir();
        if (data)
        {
            delete [] data;
            data = NULL;
            std::cout<< "delete data" << std::endl;
        }



    }
    void debug()
    {
            cout << data <<endl;
    }
    void print_dir()
    {
        printf("location: %p\n",data);
    }
    private:
    char *data;
};

int main()
{
    XHandler wm("hello"), wb("there");
    wm.debug();
    wb.debug();
    wm.print_dir();
    wb.print_dir();
    XHandler wc (wm);
    wc.print_dir();
    wc.debug();
    XHandler wd;
    wd = wc;
    wd.debug();
}

您的
操作符=
需要返回对
XHandler
的引用。。。添加一行,说明
return*this。(注意,它不能解决崩溃问题,但它是不正确的。在删除数组时也要使用delete[]。除非我弄错了,
new char(strlen(str)+1)
不会做你认为它会做的事。(使用
new char[strlen(str)+1)]
)崩溃只是让你的系统告诉你它正在尝试调试的好方法,你调用的是UB,这是错误的。(这意味着,它崩溃的原因是由运行时添加的检查,以帮助您进行调试,而不是语言的一项功能)
strcpy
复制终止的
'\0'
,除非有人在我不看的时候大量更改strcpy,否则它会复制
\0
终止符。您在
删除[]之前添加了一个测试
if(data)
。这是多余的,
delete[]
已经测试过了(常规的
delete
)。
#include <iostream>
#include <cstring>
#include <stdio.h>
using namespace std;

class XHandler
{
    public:
    XHandler()
    {
            data = new char[8];
            strcpy(data, "NoName");
            std::cout<< "default construcor is called" << std::endl;
    }
    XHandler (const char *str)
    {
            data = new char [strlen(str) + 1 ];
            strcpy (data, str);
             std::cout<< "param construcor is called" << std::endl;

    }
    XHandler (const XHandler &xh)
    {
            data = xh.data;
            std::cout<< "copy construcor is called" << std::endl;

    }
    XHandler& operator = (const XHandler &xh)
    {
            data = xh.data;
            std::cout<< "operator construcor is called" << std::endl;

            return *this;
    }
    ~XHandler()
    {
        std::cout<< "destrucor is called" << std::endl;
        print_dir();
        if (data)
        {
            delete [] data;
            data = NULL;
            std::cout<< "delete data" << std::endl;
        }



    }
    void debug()
    {
            cout << data <<endl;
    }
    void print_dir()
    {
        printf("location: %p\n",data);
    }
    private:
    char *data;
};

int main()
{
    XHandler wm("hello"), wb("there");
    wm.debug();
    wb.debug();
    wm.print_dir();
    wb.print_dir();
    XHandler wc (wm);
    wc.print_dir();
    wc.debug();
    XHandler wd;
    wd = wc;
    wd.debug();
}
param construcor is called
param construcor is called
hello
there
location: 0x502010
location: 0x502030
copy construcor is called
location: 0x502010
hello
default construcor is called
operator construcor is called
hello
destrucor is called
location: 0x502010
delete data
destrucor is called
location: 0x502010
*** glibc detected *** ./test: double free or corruption (fasttop): 0x0000000000502010 ***