Динамически указывать на существующий или создать новый объект - PullRequest
1 голос
/ 10 июля 2019

У меня есть функция, которая использует информацию, хранящуюся в структуре A. Эта функция вызывается очень часто, и большую часть времени она может просто полагаться на информацию, хранящуюся в A. При некоторых (редких) условиях один из объектов А не может быть использован. Новый объект должен быть создан, и он не должен жить дольше, чем функция (так как он может быть использован только один раз и занимает много места). У меня есть немного псевдо-кода, который демонстрирует мою проблему. На данный момент мне действительно не нравится это из-за призыва к «новому», но я не могу придумать другой способ сделать это с помощью умных указателей.

Поскольку я читал в каждой книге, что вы не должны прямо сейчас использовать указатели и полагаться на умные указатели, я не уверен, что правильно реализовать то, что я хочу.

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

Так что, в принципе, я ищу "более хороший" и безопасный способ сделать это, кто-нибудь может мне помочь? Заранее спасибо

1 Ответ

2 голосов
/ 10 июля 2019

Вы можете создать умный указатель для владения новым объектом и освободить его в конце функции, но сделайте его пустым, если вам не нужно создавать новый объект. Когда вы его создадите, просто сделайте current_data ссылкой на объект, управляемый умным указателем:

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. похоже, вы могли бы немного упростить функцию, переместив вызов reinit(i) из условных ветвей:

  // 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);

...