Skip to main content
3 of 4
added 14 characters in body
Ghita
  • 297
  • 1
  • 2
  • 10

One way to handle these is to have factory functions:

expected<Missile> Missile::Create(Params...)
expected<unique_ptr<Missile>> Missile::Create(Params...)

class Missile {
  private:
   Missile() = default;
   int Initialize(int power) // second phase constructor {
     // other operations (besides out_of_memory) that may fail
     // can be reported from this function
     expected<PowerSupply> expectedPower = PowerSupply::Create(power);
     if (!expectedPower.valid()) {
       return expectedPower.get_error();
     }
     this->power = std::move(expectedPower); // from now on power.valid() true
     return SUCCESS;
  
  public:
  static expected<Missile> Missile::Create(int p) {
    // 1. call default constructor first, this is automatic
    // storage so no fail
    // 2. Initialize called. 
    // If failure - report expected<Missile>::from_error(Initialize_STATUS);
  }
  static expected<unique_ptr<Missile>> Missile::Create(int p) {
    // 1. use operator new to construct - may fail -> expected::from_error(OUT_OF_MEMMORY)
    // 2. call Initialize and possibly report second phase errors
  }
  
  private:
  int power;
  expected<PowerSupply> power;
}

This is cleaner than using out parameters and a complex object is able (using 2 phases) to build it's dependencies, be it as automatic variable or free store allocated.

Class expected default constructor only allocates automatic storage for T. One can create an initialized expected instance by assigning a T instance to expected<T>

Ghita
  • 297
  • 1
  • 2
  • 10