0

I have two constructors in C++ and one destructor. When I use the first constructor for my object the destructor is called to delete A[] which is what I want, but when I used the second constructor I don't need to call destructor but C++ compiler calls it anyways which causes an error. What is the best way to solve this problem?

Tree(int n) {

  A = new int[n];
}

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

~Tree(){

   delete [] A;
}
Mark
  • 7,624
  • 15
  • 52
  • 76

6 Answers6

6

Store a flag indicating whether the destructor should call delete or not.

Note that you also need a user-defined copy constructor and copy assignment operator, when manually managing memory.

R. Martinho Fernandes
  • 209,766
  • 68
  • 412
  • 492
Ben Voigt
  • 260,885
  • 36
  • 380
  • 671
  • What kind of flag do I need ? – Mark Oct 12 '11 at 05:22
  • @Mark: The `bool` data type is good for flags. Make this member variable true if you allocated memory, and false if not, then in the destructor, say `if (should_delete) delete [] A;` – Ben Voigt Oct 12 '11 at 05:23
  • What if I have to use both constructors interchangeably? Does a flag really solve the problem? – Mark Oct 12 '11 at 05:29
  • 1
    @Mark: The flag is set by the constructor... the first constructor becomes: `Tree(int n) : A(new int[n]), should_delete(true) {}` I'll let you figure out the other one. – Ben Voigt Oct 12 '11 at 05:30
5

You need to use the Rule of Three in C++03 or Rule of Five in C++11 to avoid this problem.

And typically it is a bad design, In this case only way to distinguish here whether you have ownership of the dynamically allocated buffer is through a boolean flag member, which you will have to set in the constructor if you are the one allocating memory. And then before deleting in destructor you check for this flag and deallocate only if the flag is set.

Tree(int n) 
{

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

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

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

The code above is just a demonstration for using the boolean flag, You still need to follow the Rule Of Three. I already posted the link, which helps you understand what it is, I don't post the code here because I do not want you just copy paste(and I don't say you would if i added the code, but you know just in case).

Community
  • 1
  • 1
Alok Save
  • 190,255
  • 43
  • 403
  • 518
  • @Mark: Check the links in the answer. – Alok Save Oct 12 '11 at 05:22
  • It is not a complete answer. It doesn't exactly point out the problem in the OP's code. – Nawaz Oct 12 '11 at 05:24
  • 1
    You forgot the rule of three in your example code :) Could you please make it explicit that a copy constructor and copy assignment operator are missing? Or add them. – R. Martinho Fernandes Oct 12 '11 at 05:51
  • @Nawaz: What flaws are you talking about? The code just demonstrates the use of a flag to selectively delete or not delete. – Alok Save Oct 12 '11 at 05:52
  • @R. Martinho Fernandes: Just demonstration of using a flag, The first thing I mentioned and the only answer that mentioned that Op needs to follow the Rule Of Three is this.I will add a note again, hope that makes you happy. – Alok Save Oct 12 '11 at 05:54
  • @Als: The current code example is misleading, as the reader might think after adding the flag, he doesn't need to implement the copy semantic. That is what I called flawed code example. It should also be noted that with the flag, the implementation of copy-semantic is going to be different. – Nawaz Oct 12 '11 at 05:58
  • @Nawaz: I repeat this was the only answer which told the OP about **Rule of three** and the link to it, If you want me to finish his homework so that I can avoid your pedantic comments, Sorry that wont happen. – Alok Save Oct 12 '11 at 06:01
  • Als: It is completely wrong to say that yours is the only answer which talked about Rule of Three. @Ben Voigt's answer also mentions this as well, only that he said it differently, without using the *name*. – Nawaz Oct 12 '11 at 06:04
  • @Nawaz: That answer was edited **After** this answer was posted, And please stop trolling. – Alok Save Oct 12 '11 at 06:06
  • @Als: Yes. Stop Trolling. Please. ;-) – Nawaz Oct 12 '11 at 06:18
  • @Als: No, I mentioned the need from a copy constructor from the very first (no ninja edit), and did so before your answer appeared. – Ben Voigt Oct 12 '11 at 14:22
  • @BenVoigt: Yes,You mentioned copy constructor since the very first answer you posted but didn't mention the copy assignment operator,Which was added later in an edit.So technically No you didn't mention the Rule Of Three,What you mentioned was its distorted version.And Do not mis-understand me,I am not trying, neither intended to undermine your knowledge/contribution,I have seen nice answers from you over a period of time.Having said so I stand by what I said because that is true. – Alok Save Oct 12 '11 at 16:05
2

This is just a horribly flawed design imo. After the object is created, you have no idea if you're responsible for the memory or not.

Falmarri
  • 44,586
  • 38
  • 140
  • 186
  • 1
    This is more of a comment than a solution. – Ben Voigt Oct 12 '11 at 05:24
  • Unfortunately this is the starter file of my school's project. I am not allowed to change the design. Do you know a way to get around this? – Mark Oct 12 '11 at 05:25
  • I suspect it is a fine exercise for preparing one for the flawed designs in real world code-bases. ;) – visitor Oct 12 '11 at 09:30
  • @Mark: Well what are you allowed to change and what aren't you? Do you mean you need the 2 constructors? If I were doing this I would do a deep copy of the data pointer in your 2nd constructor. – Falmarri Oct 12 '11 at 23:55
  • It must run in constant time. Therefore the design is fixed. I believe deep copy would cause it run in linear time. – Mark Oct 13 '11 at 02:20
  • @Mark: What must run in constant time? The constructor? You have absolutely no idea if your constructor is running in constant time unless you override the `new` operator. And I'm not 100%, but I'm pretty sure memory allocation on the heap using `new` is almost certainly done in linear time, especially if the array gets 0'ed out. (meaning your first constructor isn't constant). – Falmarri Oct 13 '11 at 16:48
1

Set a flag that indicates if you own the data in A or not, and check it in the destructor to determine if you should free it.

In general, though, it's good to have clearly defined ownership of objects in C++; making explicit prevents memory leaks. Consider making the class always the owner of the object it contains, and having it be responsible for destroying it regardless of how it was created.

Nick Johnson
  • 98,961
  • 16
  • 125
  • 196
1

In second constructor you are assigning a pointer to an array. What I suggest you to create a heap (allocate for n elements) in second constructor and copy all elements from parameter (data) into newly created heap.

kv-prajapati
  • 90,019
  • 18
  • 141
  • 178
0

It might be worth considering using two different classes for this:

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

This has both good and bad points. On one hand, once you've created an object of the right type, everything else gets handled automatically by the type system. On the other hand, it means you have to specify the correct type at construction time, not just pass the right type of parameter. It also means most tree operations need to use a pointer or reference to a basic_tree, rather than being able to use tree objects directly. Depending on the situation, that could vary from no problem at all (e.g., if a tree will often be large enough that you're normally going to pass by reference anyway) to a massive problem, such as adding a lot of extra code to sort out the right type at creation time.

Jerry Coffin
  • 437,173
  • 71
  • 570
  • 1,035