0

Many times we need objects of some classes to be initialized in loops to be operated upon:

Suppose I have a class/structure:

class employee
{
  //member variables
  //member methods - getter/setters,etc
}

Now suppose I want to operate on each employee in an array.

Approach 1:

for (loop on array of 10 employees)
{
  employee emp(loop element);  //using constructor of employee for initialization
  //operate on the current loop element using emp
}

This way, as per my understanding, 10 emp objects will get created until the loop finishes.Now since this does not include dynamic memory allocation, once the control goes out of loop, will all 10 objects be deleted(& memory occupied by 10 will be freed) or just the last object will get deleted(& memory occupied by 9 objects will not get freed).

Approach 2:

for (loop on array of 10 employees)
{
  employee *emp=new employee(loop element);  //using constructor of employee for initialization
  //operate on the current loop element using emp
  delete emp;
  emp = nullptr;
}

Here it is in programmer's control so we can free the memory ourselves in each iteration of loop. Though this will also cause frequent allocation & freeing of heap memory & may cause some degradation in case the loop is for a huge number of employees.

Please help me with the query mentioned in Approach 1 & please suggest which one of the above approaches is good AND if there is any better approach for the same?

Ashish
  • 83
  • 1
  • 7

3 Answers3

1

Approach 1 is better since you don't need to rely on balancing new with a delete so it's less likely to leak memory: if your "operate on" code were to throw an exception in Approach 2 then delete would not be called. In Approach 1, the destructor would be called if an exception is thrown as the stack unwinds.

Conceptually yes, in both approaches, the destructor to employee will be called on each separate iteration of the loop. That said, a compiler is allowed to play about with this as an optimisation strategy if there are no side effects in doing so.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
1

I am not sure I understand the issue. If I have a loop over objects and I do not want to modify the object I would not copy them. I would just use a const reference.

for(auto const& e: employees) {
    // operate on e
}

If the object is modified, i.e. non-const member function are called, I would use a non-const reference

for(auto&& e: employees) {
    // operate on e
}

In your example, the "temporary" employee object is either stack- or heap-allocated. In the first case, the object is created on the stack. This means that the compiler simply increases (or decreases) the stack pointer to a value that there is enough space on the stack to hold an employee object and then uses the constructor to initialize it. No heap allocation will be done, and there is only one object of type employee alive plus the one from the loop. The life-time ends when the scope ends. In no case will there be ten objects at the end of the loop.

The second case is identical w.r.t life-times but allocates objects on the heap. This is much slower, but as you delete the objects all the time the life-time is identical. I would advice to use std::unique_ptr in that case, as it also is exception safe and spares you the manual memory management. You're code has a memory leak when the operation part throws an exception.

Jens
  • 9,058
  • 2
  • 26
  • 43
0

Approach 1 will allocate employee object on the stack, which is certainly faster than using the dynamic memory allocator (heap). At every iteration, the employee object will become out of scope so its descructor will be called every time. That's the good thing with the stack, it is automatically 'garbage collected' when you leave the scope (see Is a destructor called when an object goes out of scope?).

Community
  • 1
  • 1
Laurent Parenteau
  • 2,516
  • 20
  • 31