数据的双重删除不';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 ***