1

I have a function, that uses information stored in a struct A. This function is called very often and most of the time it can just rely on the information stored in A. Under some (rare) conditions, one of the objects of A cannot be used. A new object has to be created and it should not live longer than the function (since it can just be used one time and uses lots of storage). I have a little bit of pseudo code that demonstrates my problem. At the moment I really don't like it, because of the call to "new" but I can't think of another way to accomplish this with smart pointers.

As I read in every book that you should not use pointers directly nowadays and rely on smart pointers, I'm not sure, hot to implement what I want correctly.

struct A{
  myData data;
}

void often_called_function(int i, A &structA)
{

  // Pointer which shall dynamically point to existing or newly created object
  myData *current_data;

  // we rarely land here, data can't be used
  if (i == 10) {
    current_data = new myData(special arguments);
    current_data->reinit(i);
  }
  // most of the time we land here, no need to re-create data, just reinit existing data from struct A
  else {
    structA.data.reinit(i);
    current_data = &structA.data;
  }

  // do more stuff with current_data
  current_data->do_something(); 
}

So basically I'm looking for a "nicer" and safe way to accomplish this, can anybody help me? Thanks in advance

vahancho
  • 20,808
  • 3
  • 47
  • 55
mathse
  • 13
  • 2
  • what about using a `shared_ptr`? – amlucas Jul 10 '19 at 13:46
  • Wouldn't the shared pointer, If I assign "&structA.data" in the else to it try to destroy the structA.data when it goes out of scope (so after the function comes to the end)? – mathse Jul 10 '19 at 13:48

1 Answers1

2

You can create a smart pointer to own the new object and free it at the end of the function, but make it empty unless you need to create the new object. When you do create it, just make current_data refer to the object managed by the smart pointer:

void often_called_function(int i, A &structA)
{

  // Pointer which shall dynamically point to existing or newly created object
  myData *current_data;
  // smart pointer that will own the dynamically-created object, if needed:
  std::unique_ptr<myData> owner;

  // we rarely land here, data can't be used
  if (i == 10){
    owner = std::make_unique<myData>(special_arguments);
    current_data = owner.get();
    current_data->reinit(i);
  }
  // most of the time we land here, no need to re-create data, just reinit existing data from struct A
  else{
    structA.data.reinit(i);
    current_data = &structA.data;
  }

  // do more stuff with current_data
  current_data->do_something();
}

N.B. it looks like you could simplify the function a bit by moving the reinit(i) call out of the conditional branches:

  // we rarely land here, data can't be used
  if (i == 10){
    owner = std::make_unique<myData>(special_arguments);
    current_data = owner.get();
  }
  // most of the time we land here, no need to re-create data, just reinit existing data from struct A
  else{
    current_data = &structA.data;
  }
  current_data->reinit(i);

Jonathan Wakely
  • 166,810
  • 27
  • 341
  • 521