Bertrand Thelen
Bertrand Thelen

Reputation: 85

replace existing object on the stack with default constructed one

I would like to know the best/correct way to get back to the initial values of an object without playing with delete and new (everything must stay on the stack)

With this 2 classes:

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

If I need to reset some foos to their default values, what is the best way?

  1. Create reset method in Foo

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

    I don't really like the idea to have the values coming from 2 differents places and I do like to have the defaults values in the header next to the variable declaration.

  2. Replace by a locally created Foo

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

    Am I heading to trouble when the local variable is destroyed?

  3. Use memcpy

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

    Maybe less readable...

  4. Any other method?

Upvotes: 0

Views: 58

Answers (2)

Amit G.
Amit G.

Reputation: 2674

What you can do is to use std::pair on each variable. Initialized with with variable.first = variable.second = value. After, every time you want to update the variable you set: variable.second = new_value. When you want to restore to the original, you set: variable.second = variable.first. You can improve it by writing a macro RestoreDefault(var) to make the code more readable.

For example:

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

If you want to hardcoded block any possibility to re-set later the default value, write:

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

-

Addition: Same principle for array:

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

Upvotes: 0

aschepler
aschepler

Reputation: 72311

Your #2 is just fine, and probably the most legible.

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

There are no object lifetime issues here: the assignment operator is called on foos[index] to change its values to match the temporary object materialized from Foo(). That is, the code is exactly equivalent to

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

And if optimizations are enabled, almost any compiler will be able to just modify foos[index] directly without actually creating the temporary Foo.

If you do want a Foo::reset() function as well, you can use the same idea for it:

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

I would avoid using memcpy, since the program would become incorrect if you ever make changes to Foo that make it no longer trivially copyable.

Upvotes: 1

Related Questions