6

Essentially, if I create multiple instances of a new class, do I need to call the destructor for each instance, or will invoking it once destroy each instance(I apologize if I'm using vague/wrong terms, constructors/destructors are concepts I don't fully grasp yet).

To be more specific, this is some code I'm working with(I'll have to apologize again if the style is bad, I had an idea for a school problem and wanted to get the code down quickly).

while(read >> f >> l >> t >> s >> sta >> acct >> bal)
{
    cout << "test" << endl;
    ptr[i] = new account(f,l,t,s,sta,acct,bal);
    ptr[i]->printcontents();
    cout << "test" << endl;
    i++;
    cout << i << endl;
}

So for the sake of the question, assume this'll loop three times. Will I only have to invoke the destructor of "account" once to destroy all three instances of new account, or will one call leave the other two? Is this even a good practice?

Edit: I noticed some of my post got cut off, so I added the last few lines, but people have already addressed that issue. The reason I'm user pointers is purely because the assignment dictates I do so; quite frankly I don't see the point in using them at this moment, but I assume somewhere down the line they become useful. I should also add that dynamic memory allocation is also supposed to be used in the assignment.

  • 2
    Use smart pointers (i.e. `shared_ptr`/`make_shared` or `unique_ptr`/`make_unique`) and don't bother about deleting your `new`ed instances. – Torbjörn Dec 15 '16 at 15:11
  • 5
    As always: Every `new` needs exactly one `delete` and every `new[]` exactly one `delete[]`. However, you basically never need `new` and `new[]` even less often to begin with. – Baum mit Augen Dec 15 '16 at 15:13
  • 4
    The real question is why you are using pointers to begin with. Did you come from Java, where all objects are created with `new`? Your array of `account` objects could just store *actual `account` objects*. – Cody Gray - on strike Dec 15 '16 at 15:15
  • You don't *call* the destructor in C++ (except in rare circumstances, which you will not encounter for a long time, if ever). `delete` and `delete[]` do that as part of their operations, as does the destruction of automatic objects. – molbdnilo Dec 15 '16 at 15:21

5 Answers5

6

Destructors are called automatically and you usually don't have to worry about it unless you're allocating memory dynamically with new.

In that case, you will have to call delete for each allocated memory once you don't need it any more.

Note that if you're allocating an array with new [], you will have to use delete[] for desallocation:

int *a = new int[10]; // allocating an array of 10 integers

//...

delete[] a; // release memory

In modern C++, you should consider managed pointers which will do the job for you. Something like:

while(read >> f >> l >> t >> s >> sta >> acct >> bal)
{
    cout << "test" << endl;
    ptr[i] = std::make_unique<account>(f,l,t,s,sta,acct,bal);
    ptr[i]->printcontents();
    cout << "test" << endl;
    i++;
    cout << i << endl;
}

Here, std::make_unique will return a std::unique_ptr which will call delete on the associated memory when destroyed.


Last point : are you sure you really need pointers? Hard to say from your example, but depending on your usage you may as well create statically allocated objects:

while(read >> f >> l >> t >> s >> sta >> acct >> bal)
{
    cout << "test" << endl;
    ptr[i] = account(f,l,t,s,sta,acct,bal);
    ptr[i].printcontents();
    cout << "test" << endl;
    i++;
    cout << i << endl;
}
rocambille
  • 15,398
  • 12
  • 50
  • 68
  • To give a little more context, this is supposed to be part of a bank program, wherein I use an array of pointers to account objects that store account information(name, account number etc.). Initially, I declared account *ptr[10] and tried to access member function of class account(account.h is included), like this ptr[i]->setacctnum(acct); but that caused the program to crash. I don't see why this didn't work, but that's where I'm at now. – Charlie Monnone Dec 15 '16 at 16:55
  • Declaring `account *ptr[10]` creates an array of **uninitialized** pointers to account objects. That's why your program crashed: you tried to call methods on dangling pointers. You should consider avoiding pointers and declare `account ptr[10]`: you will be able to access member functions with calls like `ptr[i].setacctnum(acct);` (notice the `.` instead of `->` since `ptr[i]` is now an object instead of a pointer). If you really need pointers, consider `std::unique_ptr` – rocambille Dec 15 '16 at 17:00
3

Every new should be balanaced with a delete

If you have an array of pointers, and new each pointer, you'd need to delete each instance.

If, on the otherhand you new an array of objects, you can then delete [] the whole array.

As a side point, for your code instead of using the ptr (which you haven't told us the details of, consider just using a std::vector<account> and using push_back then it will automatically size as required, instead of ptr[i] = new....

doctorlove
  • 18,872
  • 2
  • 46
  • 62
1

Generally you have to delete each instance you create. Exactly how you do that depends a bit... but the simple rule of thumb:

For each use of new there must be a use of delete.

For each use of new[] there must be a use of delete[].

If you get the instance from an auto declaration, you don't have to do anything because it will be destroyed with its stack frame; but if you created it, you destroy it.

Mark Adelsberger
  • 42,148
  • 4
  • 35
  • 52
1

As others have noted, if you use new, then you'll need delete. However, your real trouble is conceptual. You ask a good question to which new and delete are peripheral.

The normal use of destructors, more than 99.5 percent of the time, is to let the compiler invoke them automatically. (The 0.5 percent exception is abstruse. We don't need to worry about that right now.)

Consider this code fragment:

  int n = 5;
  {
    int m = 2;
    ++m;
    n *= m;
    // The variable m is automatically destructed here.
  }
  // Here, n == 15.

See how that works? The destructor of m is automatically called when m reaches the end of its life, which (because m was not made with new) happens at the end of the block in which m is instantiated.

Of course, m is an int, so its destructor doesn't do anything (or, if you prefer, m has no destructor). Other types you yourself define, like your type account, can have destructors. The destructor is automatically called against a single object at the moment that that single object, an instance of account, reaches the end of its life.

NEW AND DELETE

So, what does this have to do with new and delete?

In my code fragment, I did not use new. Therefore, the lifetime of my object was controlled by the enclosing braces.

In your code fragment, you did use new. Therefore, the lifetime of your object is controlled by your use of delete.

Of course, you forgot to use delete, so that is why your object was never destructed (except maybe when your whole program exits).

Others have noted that modern C++ provides improved alternatives to new which you should use in most cases. You can read their answers for those. However, mechanically, it is still very helpful to understand what plain new does, and how delete pairs with it.

MANUAL INVOCATION OF THE DESTRUCTOR

You almost certainly need not worry about this, because the cases in which a destructor is manually invoked are rare and advanced. Basically, if you are managing yourself the memory in which an object is stored (which you almost never do, but there are rare exceptions), then the compiler can't tell when to destruct, so you must tell it when. See this for a typically esoteric example.

Community
  • 1
  • 1
thb
  • 13,796
  • 3
  • 40
  • 68
0

Only pointers need call the destructor to delete them or close the program

Rodrigo João Bertotti
  • 5,179
  • 2
  • 23
  • 34