Шаблоны для сброса объектов в исходное состояние

Предположим, у меня есть объект с элементом, который дорого построить, и потребность в reset() функция, которая сбрасывает его в исходное состояние:

struct Example
{
    // option 1: efficient, but need to duplicate initialization logic of reset() 
    Example(int param) : expensive_member_(param), param_(param)
    {
    }
    /* option 2: less code, but initializes expensive_member_ twice
    Example(int param) : param_(param)
    { 
        reset();
    }*/

    void reset()
    {
         expensive_member_ = ClassWithExpensiveConstructor(param_);
    }

    ClassWithExpensiveConstructor expensive_member_;
    int param_;
}

Есть ли лучший способ / шаблон для эффективного сброса объекта в исходное состояние без дублирования логики инициализации в списке инициализатора и reset функционировать?

редактировать: если нет никакого общего способа достижения того, что я хочу, это также является приемлемым результатом этого вопроса!

3 ответа

Решение

Вы можете сделать свой ExpensiveMember указатель, в таком случае ваш вариант 2 не будет вызывать ExpensiveMember конструктор в Example конструктор, если вы явно не вызываете его:

struct Example
{
    Example(int param) : expensive_member_(), param_(param)
    { 
         reset();
    }

    ~Example() {
         delete expensive_member_;   // better use unique_ptr etc
    }

    // Also a copy constructor and assignment operator 
    // are needed to avoid memory problems such as double-delete.
    // Also, better use unique_ptr etc.
    // This answer does not use unique_ptr just to make the main idea more clear.

    void reset()
    {
         delete expensive_member_;   // better use unique_ptr etc
         expensive_member_ = new ClassWithExpensiveConstructor(param_);
    }

    ClassWithExpensiveConstructor* expensive_member_;  // better use unique_ptr etc
    int param_;
}

Простым решением было бы использование (умного или обычного) указателя, так что стоимость инициализации члена (т.е. указателя) становится меньше, а фактический объект инициализируется только при вызове reset():

 struct Example
 {
    Example(int param) : param_(param)
    { 
        reset();
    }

    void reset()
    {
         p.reset(new ClassWithExpensiveConstructor(param_));
    }

    unique_ptr<ClassWithExpensiveConstructor> p;
    int param_;
}

Если ClassWithExpensiveConstructor это тот класс, чья конструкция / сброс дорогая, именно она должна оптимизировать работу.

Другим вариантом будет сохранить копию начального значения в const член, предполагая, что копирование конструкции / назначения не дорого. Это будет использовать больше памяти, но улучшить производительность, если вы звоните Example::reset() много.

struct Example
{
    Example(int param)
    : expensive_member_backup_(param)
    , expensive_member_(expensive_mamber_backup)
    , param_(param)
    {
    }

    void reset()
    {
         expensive_member_ = expensive_member_backup_;
    }

    const ClassWithExpensiveConstructor expensive_member_backup_;
    ClassWithExpensiveConstructor expensive_member_;
    int param_;
}
Другие вопросы по тегам