Dr.Evil
Dr.Evil

Reputation: 11

how to initialize an object in c++ conditionally

class X {
   X(int, int); //constructor
   void func(); 
}

class Y {
  public int func() {
    X x(5,7); 
    // some other random operations. 
    x.func(); 
  }
}

Now, if I have to just initialize x based on some conditional, how do I do it?

class Z {
 // only refer to x when mycond is true. 
  public int func(boolean mycond) {
    if(mycond) 
     X x(5,7); 
    //same random operations; 
    if(mycond) 
      x.func(); 
  }
}

One way to do the above in an unaesthetic manner is:

class Z {
  // only refer to x when mycond is true. 
  public int func(boolean mycond) {
    if(mycond)  {
       X x(5,7); 
     //same random operations; 
      x.func(); 
    }
    else  {
      //same random operations
    }
  }
}

I am looking for something more simpler where I don't have to repeat the code.

Upvotes: 1

Views: 1343

Answers (6)

lyanbo
lyanbo

Reputation: 21

your requirement is just not to repeat somethings, you could use the null object pattern.

class Base
{
};
class X : public Base
{
};
class NullX : public Base
{
};

then

int funX(boolean mycond) { 
    Base* p = NULL;
    if (mycond)
       p = new x(5,7);
    else
       p = new NullX;
    //... some other 

    //if (mycond) 
    p->func();
} 

then we could remove the second if statement.

and further more, if your my condition is only for controlling the X, then the funX will be:

int funX (Base& x)
{
   //some other
   x.func();
}

and the mycondtion will be another function,

Base* getBase(int mycond)
{
   if (mycond)
     return new X(5, 7);
   return new NullX;
}

then the function will be completely refactored.

Upvotes: 0

Miguel Grinberg
Miguel Grinberg

Reputation: 67479

The obvious solution is to use a pointer, or an auto pointer:

class Z {
public:
  // only refer to x when mycond is true. 
  int func(boolean mycond) {
    std::auto_ptr<X> px;
    if(mycond)
       px = new X(5,7); 
    //same random operations; 
    if (px.get() != 0)
      px->func(); 
  }
}

Upvotes: 1

Mankarse
Mankarse

Reputation: 40613

In the example that you gave, it is not clear why you cannot just write it as:

class Z {
    // only refer to x when mycond is true. 
    public:
    int func(bool mycond) {
        //same random operations; 
        if(mycond) {
            X x(5,7); 
            x.func();
        }
    }
};

However, if for some reason this is not desirable (for example, if the constructor for X has some side effect which must happen before "some random operations"), then you should look at boost::optional:

class Z {
    // only refer to x when mycond is true. 
    public:
    int func(bool mycond) {
        boost::optional<X> x;
        if (mycond) x = X(5,7);
        //some random operations; 
        if (mycond) x->func(); 
    }
};

If you don't want to use boost::optional for some reason, then a similar effect can be obtained with a union:

class Z {
    // only refer to x when mycond is true. 
    public:
    int func(bool mycond) {
        union OptionalX {
            OptionalX() {}
            X value;
        } x;
        if (mycond) new (&x.value) X(5,7);
        try {
            //some random operations;
            if (mycond) {
                x.value.func();
                x.value.~X();
            }
        }
        catch (...) { if (mycond) x.value.~X(); }
    }
};

That said, this will cause the introduction of a name into a scope where that name only sometimes has meaning. This is highly questionable, and you should probably consider using a different design.

Upvotes: 4

James Kanze
James Kanze

Reputation: 153909

The obvious answer is to put the other random operations in a separate function, so your code becomes:

int
func()
{
    if ( myCondition ) {
        X x( 5, 7 );
        otherOperations();
        x.func();
    } else {
        otherOperations();
    }
}

You should probably do this anyway, if only to make the function readable and maintainable.

Upvotes: 2

Azodious
Azodious

Reputation: 13872

How about using new and pointer (*)

X *xPtr = 0;
class Z 
{   
    // only refer to xPtr when mycond is true.    
    public int func(boolean mycond) 
    {
        if(mycond)  
        {        
            xPtr = new X(5,7);       
        }

        //same random operations;                 

        if(xPtr)
        {
            xPtr.func();      
        }
    }

   // and don't forget delete xPtr;
} 

and see if above code can be refactored as following:

X *xPtr = 0;
class Z 
{   
    // only refer to xPtr when mycond is true.    
    public int func(boolean mycond) 
    {
        //same random operations;                 

        if(mycond)  
        {        
            xPtr = new X(5,7);       
            xPtr.func();      
        }
    }

   // and don't forget delete xPtr;
} 

Upvotes: 0

Francesco
Francesco

Reputation: 3250

You could factor out the "random operations", like this

if (my_cond) X x(5, 7);
random_operations_factored_out(T& a, U& b, const W& c, ..); // all the references that you need
if (my_cond) X.func();

Obviously you can (should?) encapsulate the context better, I used pass-by-reference for the sake of an example.

Another possibility is to encapsulate the logic in a pair of constructor and destructor, like

class X_caller{
private:
  bool cond;
  X x;
public:
  X_caller(bool cond, int param1, int param2):cond(cond){ 
       if (cond) {x = X(param1, param2);}
  }
  ~X_caller(){
      if (cond) x.func();
  }
}

Now you will use this like this

{
X_caller(my_cond, 5, 7);
// all your operations

} // at the end of the scope the destructor of X_caller calls x.func() only if my_cond was true
  // but you "can't see" this function call if you don't know the body of X_caller, so be careful!
  // You have to document this kind of behaviour otherwise it's too obscure for future maintenance.

In all cases you have to make sure that all the resources (variables etc) which must be accessed are available to the factored out code.

The balance between the various choices depends on the complexity of the code: always try to reduce potential confusion in the reader of the code. This could come from long repeated piece of codes, or from "hidden" calls or from many other source, and you should try to reduce it if possible.

Upvotes: 0

Related Questions