anderas
anderas

Reputation: 5854

Patterns for resetting objects to initial state

Suppose I have an object with a member that is expensive to construct, and the need for a reset() function that resets it to its initial state:

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_;
}

Is there a better way of/pattern for efficiently resetting the object to its initial state without duplicating the initialization logic in the initializer list and the reset function?

edit: If there is no generic way of achieving what I want, that is also an acceptable outcome of this question!

Upvotes: 3

Views: 1384

Answers (3)

Petr
Petr

Reputation: 10007

You can make your ExpensiveMember a pointer, in such case your option 2 will not call ExpensiveMember constructor in Example constructor unless you explicitly call it:

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_;
}

Upvotes: 1

kiviak
kiviak

Reputation: 1103

A simple solution would be to use a (smart or regular) pointer, so that the cost of initializing the member (i.e. the pointer) becomes smaller, and the actual object is only initialized in the call to reset():

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

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

    unique_ptr<ClassWithExpensiveConstructor> p;
    int param_;
}

Upvotes: 1

Antonio P&#233;rez
Antonio P&#233;rez

Reputation: 7002

If ClassWithExpensiveConstructor is the one class whose construction/reset is expensive, it should be it which optimizes the operation.

Another option would be to keep a copy of the initial value in a const member, assuming that copy construction/assignment is not expensive. That would use more memory, but improve performance if you happen to call Example::reset() a lot.

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_;
}

Upvotes: 1

Related Questions