我在C ++中有两个构造函数和一个析构函数。当我为我的对象使用第一个构造函数时,析构函数被调用以删除A []这是我想要的,但是当我使用第二个构造函数时,我不需要调用析构函数,但C ++编译器无论如何调用它会导致错误。解决这个问题的最佳方法是什么?
Tree(int n) {
A = new int[n];
}
Tree(int data*, int n) {
A = data;
}
~Tree(){
delete [] A;
}
答案 0 :(得分:6)
存储一个标志,指示析构函数是否应该调用delete。
请注意,在手动管理内存时,还需要用户定义的复制构造函数和复制赋值运算符。
答案 1 :(得分:5)
您需要在C ++ 03中使用 Rule of Three 或在C ++ 11中使用 Rule of Five 来避免此问题。
通常它是一个糟糕的设计,在这种情况下,只有这样才能区分你是否拥有动态分配缓冲区的所有权是通过一个布尔标志成员,如果你是一个分配你必须在构造函数中设置记忆。然后在析构函数中删除之前,检查此标志并仅在设置了标志时解除分配。
Tree(int n)
{
A = new int[n];
OwnFlag = true;
}
Tree(int data*, int n)
{
A = data;
OwnFlag = false;
}
~Tree()
{
if(OwnFlag)
delete [] A;
}
上面的代码只是使用布尔标志的演示,您仍然需要遵循三个规则。我已经发布了链接,这可以帮助你理解它是什么,我不在这里发布代码,因为我不希望你只是复制粘贴(我不会说你会添加代码,但你知道只是在案件中)。
答案 2 :(得分:2)
这只是一个非常有缺陷的设计imo。创建对象后,您不知道自己是否对内存负责。
答案 3 :(得分:1)
设置一个标志,指示您是否拥有A中的数据,并在析构函数中检查它以确定是否应该释放它。
但总的来说,在C ++中明确定义对象的所有权是件好事。明确防止内存泄漏。考虑使类始终是它包含的对象的所有者,并让它负责销毁它,无论它是如何创建的。
答案 4 :(得分:1)
在第二个构造函数中,您正在分配pointer to an array
。我建议您在第二个构造函数中创建heap
(为n个元素分配)并将参数(data
)中的所有元素复制到新创建的heap
。
答案 5 :(得分:0)
可能值得考虑使用两个不同的类:
struct basic_tree {
virtual ~basic_tree();
};
// Warning: incomplete -- at the very least, this almost certainly needs to
// define its own assignment operator and copy ctor (aka the rule of three),
// or else declare them private to prevent them (or use `=delete` in C++11).
//
class owning_tree : public basic_tree {
int *A;
public:
owning_tree(int n) : A(new int[n]) {}
~owning_tree() { delete [] A; }
};
class non_owning_tree : public basic_tree {
int *A;
public:
non_owning_tree(int *data) : A(data) {}
};
这有好有坏。一方面,一旦您创建了正确类型的对象,其他所有内容都将由类型系统自动处理。另一方面,这意味着您必须在构造时指定正确的类型,而不仅仅是传递正确类型的参数。它还意味着大多数树操作需要使用指向basic_tree的指针或引用,而不是直接使用树对象。根据具体情况,可能会出现任何问题(例如,如果一棵树通常足够大,通常无论如何都会通过引用传递),也会出现大问题,例如添加大量额外代码在创建时挑选出正确的类型。