析构函数无法删除已分配的连续内存块
The destructor is unable to delete a continuous memory block that has been allocated
以下代码可以编译但在 运行 时间内出现错误:
# include <iostream>
# include <string.h>
class A {
public:
A() {}
A ( int id, char * t_name ) {
_id = id ;
name = new char [ strlen (t_name) + 1 ] ;
strcpy ( name, t_name ) ;
}
char *name ;
int _id ;
~A() { delete [] name ;}
} ;
int main () {
A a ( 1, "123" ) ;
A b ;
b = a ;
std::cout << static_cast < const void * > ( a.name ) << std::endl ;
std::cout << static_cast < const void * > ( b.name ) << std::endl ;
b.name = "abc" ; // b.name is directed to a different memory block
std::cout << static_cast < const void * > ( a.name ) << std::endl ;
std::cout << static_cast < const void * > ( b.name ) << std::endl ;
std::cout << a.name << std::endl ;
std::cout << b.name << std::endl ;
return 0 ;
}
它输出如下内容:
0x7ff87bc03200
0x7ff87bc03200
0x7ff87bc03200
0x10f9bcf64
123
abc
a.out(883,0x7fff7ee3d000) malloc: *** error for object 0x10f9bcf64:
pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
Abort trap: 6
我不明白为什么说:
0x10f9bcf64: pointer being freed was not allocated
因为 b.name
显然指向 0x10f9bcf64
,并且不再与 a
重叠!
我也想知道如何解决这个问题?谢谢!
您正在将指针从实例 a 复制到实例 b。
当实例a的析构函数运行时,它会删除内存。
实例b的析构函数运行时,再次删除相同的内存。
您需要为此class 添加一个复制和赋值构造函数。 (如果您使用的是 c++11,还有移动构造函数)
I do not understand why it says "0x10f9bcf64: pointer being freed was
not allocated" since b.name is obviously directed to 0x10f9bcf64 and
does not overlap with a's any more!
因为 b
的析构函数正在静态字符串上调用 delete []
。
I also wonder how this issue could be addressed.
你应该已经定义了一个复制构造函数,比如:
A::A(const A& lhs) {
_id = lhs.id;
name = new char [ strlen (lhs.name) + 1 ] ;
strcpy ( name, lhs.name ) ;
}
并且还制作了name
和_id
private
。
对于初学者来说,构造函数声明应该如下所示
A ( int id, const char * t_name )
^^^^^^
因为您正在使用字符串文字来初始化 class 的对象,并且字符串文字具有常量数组类型。
默认的复制赋值运算符对对象的数据成员进行逐成员复制。相对于此语句后的代码
b = a ;
对象将有两个指针指向同一个动态分配的内存。因此,删除运算符将针对同一内存地址调用两次。
您必须为您的 class 显式编写复制赋值运算符和复制构造函数。
例如,复制赋值运算符可以如下所示
A & operator = ( const A &a )
{
if ( this != &a )
{
char *tmp = new char[ std::strlen( a.name ) + 1 ];
std::strcpy( tmp, a.name );
delete [] this->name;
this->_id = a._id;
this->name = tmp;
}
return *this;
}
这条语句
b.name = "abc"
也是错误的。字符串文字具有静态存储持续时间。所以你不能删除他们的记忆。
您应该先阅读有关 Rule of 3/5/0 的内容。您的陈述:
b = a;
违反规则 3(如果您使用的是现代 C++,即 C++11 或更高版本,则为 5),因为您的 class A
有一个指针作为成员.
接下来,如果您考虑以下陈述:
b.name = "abc";
您在这里影响的是您未使用 new
分配的静态字符数组。所以当你的析构函数试图删除它时:
~A() { delete [] name ;}
对 delete[]
的调用产生了您的错误。
一个简单的解决方案是将 name
声明为 std::string
:
class A {
public:
A () {}
A ( int id, const std::string& t_name ) {
_id = id ;
name = t_name;
}
std::string name ;
int _id ;
} ;
int main () {
A a ( 1, "123" ) ;
A b ;
b = a ;
std::cout << static_cast < const void * > ( &a.name ) << std::endl ;
std::cout << static_cast < const void * > ( &b.name ) << std::endl ;
b.name = "abc" ; // b.name is directed to a different memory block
std::cout << static_cast < const void * > ( &a.name ) << std::endl ;
std::cout << static_cast < const void * > ( &b.name ) << std::endl ;
std::cout << a.name << std::endl ;
std::cout << b.name << std::endl ;
return 0 ;
}
由于std::string
为您管理内存,您又回到了0规则的精彩世界。
以下代码可以编译但在 运行 时间内出现错误:
# include <iostream>
# include <string.h>
class A {
public:
A() {}
A ( int id, char * t_name ) {
_id = id ;
name = new char [ strlen (t_name) + 1 ] ;
strcpy ( name, t_name ) ;
}
char *name ;
int _id ;
~A() { delete [] name ;}
} ;
int main () {
A a ( 1, "123" ) ;
A b ;
b = a ;
std::cout << static_cast < const void * > ( a.name ) << std::endl ;
std::cout << static_cast < const void * > ( b.name ) << std::endl ;
b.name = "abc" ; // b.name is directed to a different memory block
std::cout << static_cast < const void * > ( a.name ) << std::endl ;
std::cout << static_cast < const void * > ( b.name ) << std::endl ;
std::cout << a.name << std::endl ;
std::cout << b.name << std::endl ;
return 0 ;
}
它输出如下内容:
0x7ff87bc03200
0x7ff87bc03200
0x7ff87bc03200
0x10f9bcf64
123
abc
a.out(883,0x7fff7ee3d000) malloc: *** error for object 0x10f9bcf64:
pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
Abort trap: 6
我不明白为什么说:
0x10f9bcf64: pointer being freed was not allocated
因为 b.name
显然指向 0x10f9bcf64
,并且不再与 a
重叠!
我也想知道如何解决这个问题?谢谢!
您正在将指针从实例 a 复制到实例 b。
当实例a的析构函数运行时,它会删除内存。
实例b的析构函数运行时,再次删除相同的内存。
您需要为此class 添加一个复制和赋值构造函数。 (如果您使用的是 c++11,还有移动构造函数)
I do not understand why it says "0x10f9bcf64: pointer being freed was not allocated" since b.name is obviously directed to 0x10f9bcf64 and does not overlap with a's any more!
因为 b
的析构函数正在静态字符串上调用 delete []
。
I also wonder how this issue could be addressed.
你应该已经定义了一个复制构造函数,比如:
A::A(const A& lhs) {
_id = lhs.id;
name = new char [ strlen (lhs.name) + 1 ] ;
strcpy ( name, lhs.name ) ;
}
并且还制作了name
和_id
private
。
对于初学者来说,构造函数声明应该如下所示
A ( int id, const char * t_name )
^^^^^^
因为您正在使用字符串文字来初始化 class 的对象,并且字符串文字具有常量数组类型。
默认的复制赋值运算符对对象的数据成员进行逐成员复制。相对于此语句后的代码
b = a ;
对象将有两个指针指向同一个动态分配的内存。因此,删除运算符将针对同一内存地址调用两次。
您必须为您的 class 显式编写复制赋值运算符和复制构造函数。
例如,复制赋值运算符可以如下所示
A & operator = ( const A &a )
{
if ( this != &a )
{
char *tmp = new char[ std::strlen( a.name ) + 1 ];
std::strcpy( tmp, a.name );
delete [] this->name;
this->_id = a._id;
this->name = tmp;
}
return *this;
}
这条语句
b.name = "abc"
也是错误的。字符串文字具有静态存储持续时间。所以你不能删除他们的记忆。
您应该先阅读有关 Rule of 3/5/0 的内容。您的陈述:
b = a;
违反规则 3(如果您使用的是现代 C++,即 C++11 或更高版本,则为 5),因为您的 class A
有一个指针作为成员.
接下来,如果您考虑以下陈述:
b.name = "abc";
您在这里影响的是您未使用 new
分配的静态字符数组。所以当你的析构函数试图删除它时:
~A() { delete [] name ;}
对 delete[]
的调用产生了您的错误。
一个简单的解决方案是将 name
声明为 std::string
:
class A {
public:
A () {}
A ( int id, const std::string& t_name ) {
_id = id ;
name = t_name;
}
std::string name ;
int _id ;
} ;
int main () {
A a ( 1, "123" ) ;
A b ;
b = a ;
std::cout << static_cast < const void * > ( &a.name ) << std::endl ;
std::cout << static_cast < const void * > ( &b.name ) << std::endl ;
b.name = "abc" ; // b.name is directed to a different memory block
std::cout << static_cast < const void * > ( &a.name ) << std::endl ;
std::cout << static_cast < const void * > ( &b.name ) << std::endl ;
std::cout << a.name << std::endl ;
std::cout << b.name << std::endl ;
return 0 ;
}
由于std::string
为您管理内存,您又回到了0规则的精彩世界。