我似乎遇到动态内存分配问题。
在下面,您将看到一个派生类,其中包含将使用void name(const char* name)
方法动态分配的名称变量的指针。该函数由Product构造函数运行,该构造函数在创建对象时为产品类设置名称。这是班级:
namespace sict {
class Product :public Streamable {
char* name_;
public:
Product(const char* name);
virtual ~Product();
void name(const char* name);
}
这里有名称函数本身,以及一个参数构造函数:
void sict::Product::name(const char * name) {
int g = strlen(name);
name_ = new char[g];
strncpy(name_, name, g);
name_[g] = 0;
}
Product::~Product() {
delete [] name_;
name_ = nullptr;
}
对我来说,这个代码似乎足以创建对象,然后在它退出运行它的函数范围时安静地销毁它。但是,当函数结束并且析构函数运行时,程序会冻结/崩溃在delete [] name_
。在Visual Studio的编译器上运行该程序似乎没有产生任何特定错误(程序冻结除外),但gcc编译器检测到某种堆损坏。有人会知道为什么会这样吗?
答案 0 :(得分:3)
我不确定为什么Sean Cline没有发表评论作为答案,但肖恩是正确的。
name_
被赋予g
个元素,然后name_[g]
被设置为零,但name_[g]
是一个超过数组末尾的元素。使用name_ = new char[g+1];
或name_[g-1] = 0;
,这样就不会超过数组的末尾。
另外,正如几条评论所指出的,每当你有一个动态分配内存的类时,请确保定义复制构造函数,赋值运算符,以及的析即可。如果您错过了一个,默认实现将执行浅拷贝,这可能会让您感到头痛。
浅拷贝是复制指针而不是指向的数据。在你的情况下,如果复制或分配了这个类的对象,你最终会得到两个指向堆上相同数据的对象,并且当它们运行析构函数时它们都会尝试删除它。
有关这些功能的更多信息,请参阅Rule of Three