free():在调用重载赋值运算符时在 tcache 2 中检测到双重释放
free(): double free detected in tcache 2 on calling overloaded assignment operator
我正在做一个大学项目,我们要将一些 c++ 字符串 class 实现为 Mystring。我正在研究重载赋值运算符,这是它的当前代码:
Mystring& Mystring::operator=(const Mystring& orig)
{
if(this != &orig)
{
delete ptr_buffer;
len = orig.len;
buf_size = orig.buf_size;
ptr_buffer = orig.ptr_buffer;
}
return *this;
}
ptr_buffer, 长度。和 buf_size 是 Mystring class 的三个私有变量。这是我要测试的主要程序:
void check (const Mystring s, const string name)
{
cout << "checking " << name << endl;
cout << name << " contains " << s << endl;
cout << name << " capacity() is " << s.capacity() << endl;
cout << name << " length() is " << s.length() << endl;
cout << name << " size() is " << s.size() << endl;
cout << name << " max_size() is " << s.max_size() << endl << endl;
}
int main()
{
Mystring s1("Hi there!");
check(s1, "s1");
Mystring s2("Testing before assignment!");
check(s2, "s2");
s2 = s1;
check(s2, "s2");
return 0;
}
这是输出的内容:
checking s1
s1 contains Hi there!
s1 capacity() is 10
s1 length() is 9
s1 size() is 9
s1 max_size() is 1073741820
checking s2
s2 contains Testing before assignment!
s2 capacity() is 27
s2 length() is 26
s2 size() is 26
s2 max_size() is 1073741820
checking s2
s2 contains Hi there!
s2 capacity() is 10
s2 length() is 9
s2 size() is 9
s2 max_size() is 1073741820
free(): double free detected in tcache 2
Process finished with exit code 134 (interrupted by signal 6: SIGABRT)
如您所见,赋值确实可以设置所有成员变量,但是我得到一个非零退出代码和一个 free(): double free detected in tcache 2 错误。我做错了什么,这个错误是什么意思?我已经确认退出代码来自调用赋值,因为当我注释掉 s2 = s1; 时,它以退出代码 0 完成。
据推测,Mystring
具有如下所示的析构函数:
Mystring::~Mystring() {
delete[] ptr_buffer;
}
因此,您不能只从 orig
获取 ptr_buffer
的所有权而不用其他东西替换它。这在 move-assignment 中是可行的,但是因为你在 copy-assignment 中,所以你必须保持 orig
不变。
这意味着您必须将 orig
的数据复制到其中,必要时分配一个新数据:
Mystring& Mystring::operator=(const Mystring& orig)
{
if(this != &orig)
{
std::size_t min_buf_size = orig.len + 1; // or perhaps orig.buf_size, it depends.
// no need to allocate a new buffer if the current one is big enough already.
if(buf_size < min_buf_size) {
delete[] ptr_buffer;
buf_size = min_buf_size;
ptr_buffer = new char[buf_size];
}
len = orig.len;
assert(buf_size >= len + 1);
std::memcpy(ptr_buffer, orig.ptr_buffer, len + 1);
}
return *this;
}
在此复制赋值运算符
Mystring& Mystring::operator=(const Mystring& orig)
{
if(this != &orig)
{
delete ptr_buffer;
len = orig.len;
buf_size = orig.buf_size;
ptr_buffer = orig.ptr_buffer;
}
return *this;
}
至少有两个问题。如果指针 ptr_buffer
指向的字符数组是动态分配的,那么您必须使用运算符 delete []
而不是 delete
delete [] ptr_buffer;
第二个问题就是这个赋值后
ptr_buffer = orig.ptr_buffer;
两个指针指向同一个动态分配的内存。
您需要分配一个新的扩展内存并将分配对象的字符串复制到那里。
运算符至少可以这样定义
Mystring & Mystring::operator =( const Mystring &orig )
{
if(this != &orig)
{
if ( buf_size != orig.buf_size )
{
delete [] ptr_buffer;
ptr_buffer = new char[orig.buf_size];
buf_size = orig.buf_size;
}
len = orig.len;
strcpy( ptr_buffer, orig.ptr_buffer );
// or if the class does not store strings then
// memcpy( ptr_buffer, orig.ptr_buffer, len );
}
return *this;
}
我正在做一个大学项目,我们要将一些 c++ 字符串 class 实现为 Mystring。我正在研究重载赋值运算符,这是它的当前代码:
Mystring& Mystring::operator=(const Mystring& orig)
{
if(this != &orig)
{
delete ptr_buffer;
len = orig.len;
buf_size = orig.buf_size;
ptr_buffer = orig.ptr_buffer;
}
return *this;
}
ptr_buffer, 长度。和 buf_size 是 Mystring class 的三个私有变量。这是我要测试的主要程序:
void check (const Mystring s, const string name)
{
cout << "checking " << name << endl;
cout << name << " contains " << s << endl;
cout << name << " capacity() is " << s.capacity() << endl;
cout << name << " length() is " << s.length() << endl;
cout << name << " size() is " << s.size() << endl;
cout << name << " max_size() is " << s.max_size() << endl << endl;
}
int main()
{
Mystring s1("Hi there!");
check(s1, "s1");
Mystring s2("Testing before assignment!");
check(s2, "s2");
s2 = s1;
check(s2, "s2");
return 0;
}
这是输出的内容:
checking s1
s1 contains Hi there!
s1 capacity() is 10
s1 length() is 9
s1 size() is 9
s1 max_size() is 1073741820
checking s2
s2 contains Testing before assignment!
s2 capacity() is 27
s2 length() is 26
s2 size() is 26
s2 max_size() is 1073741820
checking s2
s2 contains Hi there!
s2 capacity() is 10
s2 length() is 9
s2 size() is 9
s2 max_size() is 1073741820
free(): double free detected in tcache 2
Process finished with exit code 134 (interrupted by signal 6: SIGABRT)
如您所见,赋值确实可以设置所有成员变量,但是我得到一个非零退出代码和一个 free(): double free detected in tcache 2 错误。我做错了什么,这个错误是什么意思?我已经确认退出代码来自调用赋值,因为当我注释掉 s2 = s1; 时,它以退出代码 0 完成。
据推测,Mystring
具有如下所示的析构函数:
Mystring::~Mystring() {
delete[] ptr_buffer;
}
因此,您不能只从 orig
获取 ptr_buffer
的所有权而不用其他东西替换它。这在 move-assignment 中是可行的,但是因为你在 copy-assignment 中,所以你必须保持 orig
不变。
这意味着您必须将 orig
的数据复制到其中,必要时分配一个新数据:
Mystring& Mystring::operator=(const Mystring& orig)
{
if(this != &orig)
{
std::size_t min_buf_size = orig.len + 1; // or perhaps orig.buf_size, it depends.
// no need to allocate a new buffer if the current one is big enough already.
if(buf_size < min_buf_size) {
delete[] ptr_buffer;
buf_size = min_buf_size;
ptr_buffer = new char[buf_size];
}
len = orig.len;
assert(buf_size >= len + 1);
std::memcpy(ptr_buffer, orig.ptr_buffer, len + 1);
}
return *this;
}
在此复制赋值运算符
Mystring& Mystring::operator=(const Mystring& orig)
{
if(this != &orig)
{
delete ptr_buffer;
len = orig.len;
buf_size = orig.buf_size;
ptr_buffer = orig.ptr_buffer;
}
return *this;
}
至少有两个问题。如果指针 ptr_buffer
指向的字符数组是动态分配的,那么您必须使用运算符 delete []
而不是 delete
delete [] ptr_buffer;
第二个问题就是这个赋值后
ptr_buffer = orig.ptr_buffer;
两个指针指向同一个动态分配的内存。
您需要分配一个新的扩展内存并将分配对象的字符串复制到那里。
运算符至少可以这样定义
Mystring & Mystring::operator =( const Mystring &orig )
{
if(this != &orig)
{
if ( buf_size != orig.buf_size )
{
delete [] ptr_buffer;
ptr_buffer = new char[orig.buf_size];
buf_size = orig.buf_size;
}
len = orig.len;
strcpy( ptr_buffer, orig.ptr_buffer );
// or if the class does not store strings then
// memcpy( ptr_buffer, orig.ptr_buffer, len );
}
return *this;
}