заменить существующий объект в стеке созданным по умолчанию - PullRequest
0 голосов
/ 02 июля 2018

Я хотел бы знать лучший / правильный способ возврата к начальным значениям объекта, не играя с delete и new (все должно оставаться в стеке)

При этом 2 класса:

static const int defaultValue{15};
class Foo
{
  private: 
     int val1{defaultValue};
     short val2{4};
} 
class LongStandingObject
{
   public:
     void resetFoo(int index);
   private:
     Foo foos[100];
}

Если мне нужно сбросить некоторые foos к их значениям по умолчанию, как лучше всего?

  1. Создать метод сброса в Foo

    void Foo::reset()
    {
       val1 = defaultValue;
       val2 = 4;
    }
    

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

  2. Заменить на локально созданный Foo

    void LongStandingObject::resetFoo(int index)
    {
       foos[index] = Foo();
    }
    

    Могу ли я столкнуться с проблемой, когда локальная переменная уничтожена?

  3. Используйте memcpy

    void LongStandingObject::resetFoo(int index)
    {
       Foo foo;
       memcpy(foos[index], &foo, sizeof(Foo));
    }
    

    Возможно, менее читабельный ...

  4. Любой другой метод?

Ответы [ 2 ]

0 голосов
/ 02 июля 2018

Ваш # 2 в порядке, и, вероятно, самый разборчивый.

void LongStandingObject::resetFoo(int index)
{
   foos[index] = Foo();
}

Здесь нет проблем с продолжительностью жизни объекта: оператор присваивания вызывается на foos[index], чтобы изменить его значения в соответствии с временным объектом, материализованным из Foo(). То есть код в точности эквивалентен

{
    Foo tmp;
    foos[index].val1 = tmp.val1;
    foos[index].val2 = tmp.val2;
}

И если оптимизация включена, почти любой компилятор сможет просто изменить foos[index] напрямую, без фактического создания временного Foo.

Если вам действительно нужна функция Foo::reset(), вы можете использовать ту же идею для нее:

void Foo::reset()
{
    *this = Foo();
}

Я бы не стал использовать memcpy, так как программа стала бы некорректной, если вы когда-нибудь внесете изменения в Foo, которые сделают ее более нетривиально копируемой.

0 голосов
/ 02 июля 2018

Что вы можете сделать, это использовать std :: pair для каждой переменной. Инициализируется с помощью variable.first = variable.second = value. После каждого раза, когда вы хотите обновить установленную переменную: variable.second = new_value. Если вы хотите восстановить оригинал, вы устанавливаете: variable.second = variable.first. Вы можете улучшить его, написав макрос RestoreDefault(var), чтобы сделать код более читабельным.

Например:

#define RestoreDefault(var) ((var).second = (var).first)

// int val1{180}; // Instead of this line
std::pair<int,int> val1{ 180,180}; // <- this line

val1.second = 456;
RestoreDefault(val1);

Если вы хотите в жестком коде заблокировать любую возможность позже установить значение по умолчанию, напишите:

std::pair<const int,int> val1{ 180,180}; // <- this line

-

Добавление: тот же принцип для массива:

class Foo
{
public:
    int x = 100;
    int y = 200;
};

#define RestoreArrDefault(var) ((var).second.fill((var).first))

// Use:

std::pair<Foo, std::array<Foo, 100>> FooAr, FooAr2;

// You can define different arrays with different defaults:
FooAr.first = { 180,360 }; // <- Customize FooAr defaults

// In that point FooAr default is 180,360 and FooAr2 default is 100,200

FooAr.second[3] = { 2,10 }; // <- Edit FooAr index-3 item
RestoreArrDefault(FooAr); // <- Restore Default
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...