多个构造函数的析构函数 我有两个C++构造函数和一个析构函数。当我使用对象的第一个构造函数时,调用析构函数来删除一个[A],这是我想要的,但是当我使用第二个构造函数时,我不需要调用析构函数,但是C++编译器调用它无论如何都会导致错误。解决这个问题的最好办法是什么 Tree(int n) { A = new int[n]; } Tree(int data*, int n) { A = data; } ~Tree(){ delete [] A; }

多个构造函数的析构函数 我有两个C++构造函数和一个析构函数。当我使用对象的第一个构造函数时,调用析构函数来删除一个[A],这是我想要的,但是当我使用第二个构造函数时,我不需要调用析构函数,但是C++编译器调用它无论如何都会导致错误。解决这个问题的最好办法是什么 Tree(int n) { A = new int[n]; } Tree(int data*, int n) { A = data; } ~Tree(){ delete [] A; },c++,C++,您需要在C++03或C++11中使用以避免此问题 通常,这是一个糟糕的设计,在这种情况下,区分您是否拥有动态分配的缓冲区的唯一方法是通过布尔标志成员,如果您是分配内存的人,则必须在构造函数中设置布尔标志成员。然后,在析构函数中删除之前,检查此标志,并仅在设置该标志时解除分配 Tree(int n) { A = new int[n]; OwnFlag = true; } Tree(int data*, int n) { A = data; OwnFlag = false

您需要在C++03或C++11中使用以避免此问题

通常,这是一个糟糕的设计,在这种情况下,区分您是否拥有动态分配的缓冲区的唯一方法是通过布尔标志成员,如果您是分配内存的人,则必须在构造函数中设置布尔标志成员。然后,在析构函数中删除之前,检查此标志,并仅在设置该标志时解除分配

Tree(int n) 
{

  A = new int[n];
  OwnFlag = true;
}

Tree(int data*, int n) 
{
   A = data;
   OwnFlag = false;
}

~Tree()
{
  if(OwnFlag)
      delete [] A;
}

上面的代码只是使用布尔标志的一个演示,您仍然需要遵循三的规则。我已经发布了链接,这有助于你理解它是什么,我不在这里发布代码,因为我不希望你只是复制粘贴,我也不说如果我添加了代码,你会这么做,但你知道以防万一。

存储一个标志,指示析构函数是否应该调用delete


请注意,在手动管理内存时,您还需要一个用户定义的复制构造函数和复制分配操作符。

这只是一个有严重缺陷的设计。创建对象后,您不知道是否要对内存负责。

设置一个标志,指示您是否拥有内存中的数据,并在析构函数中检查它,以确定是否应该释放它


一般来说,在C++中有明确定义的对象所有权是有益的;显式设置可以防止内存泄漏。考虑让类始终是它包含的对象的所有者,并且不管它是如何创建的,它都有责任破坏它。

在第二个构造函数中,你给一个数组分配一个指针。我建议您在第二个构造函数中为n个元素创建一个heap allocate,并将参数数据中的所有元素复制到新创建的heap中。

为此,可能需要考虑使用两个不同的类:

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) {}
};

这既有优点也有缺点。一方面,一旦创建了正确类型的对象,其他所有内容都会由类型系统自动处理。另一方面,这意味着您必须在构造时指定正确的类型,而不仅仅是传递正确类型的参数。这也意味着大多数树操作需要使用指向基本树的指针或引用,而不是直接使用树对象。视情况而定,这可能与完全没有问题不同,例如,如果一棵树通常足够大,您通常会通过引用传递给一个大问题,例如在创建时添加大量额外代码来排序正确的类型。

我需要什么样的标志?@Mark:bool数据类型适用于标志。如果已分配内存,则将此成员变量设为true;如果未分配内存,则设为false,然后在析构函数中,说明是否应删除[]A;如果我必须交替使用这两个构造函数呢?标志真的能解决问题吗?@Mark:标志是由构造函数设置的。。。第一个构造函数变成:Treeint n:Anew int[n],应该是{deletetrue{}我会让你找出另一个。@Mark:检查答案中的链接。这不是一个完整的答案。它没有准确指出OP代码中的问题。您忘记了示例代码中的三条规则:您能明确说明缺少复制构造函数和复制赋值运算符吗?或者添加它们。@Nawaz:你在说什么缺陷?代码只是演示了如何使用标志来选择性地删除或不删除。@R.Martinho Fernandes:只是演示了如何使用标志,我提到的第一件事,也是唯一提到Op需要遵循三的规则的答案是。我将再次添加注释,希望这能让你开心。这更多的是一个评论,而不是一个解决方案。不幸的是,这是我学校项目的起始文件。我不允许改变设计。你知道解决这个问题的方法吗?我怀疑这是一个很好的练习,可以为现实世界代码库中有缺陷的设计做准备@马克:那么什么是允许你改变的,什么是不允许的?你的意思是你需要两个构造器吗?如果我这样做的话,我会在你的第二个构造函数中做一个数据指针的深度拷贝。它必须在固定时间内运行。因此,设计是固定的。我相信深度复制会导致它以线性时间运行。