c++stlraiicode-structurefinalization

C++ automatic finalization or objects destruction


In this example I faced the problem of copying the code:

void BadExample1() {
  if (!Initialize1())
    return;

  if (!Initialize2())  {
    Finalize1();
    return;
  }

  if (!Initialize3())  {
    Finalize1();
    Finalize2();
    return;
  }

  if (!Initialize4()) {
    Finalize1();
    Finalize2();
    Finalize3();
    return;
  }

  // some code..

  Finalize1();
  Finalize2();
  Finalize3();
  Finalize4();
}

Bnd here is a bad code structure. If I have a lot of constructs, the width of the code will be too large, this is also bad:

void BadExample2() {
  if (Initialize1()) {
    if (Initialize2()) {
      if (Initialize3()) {
        if (Initialize4()) {
          if (Initialize5()) {
            // some code..

            Finalize5();
          }
          Finalize4();
        }
        Finalize3();
      }
      Finalize2();
    }
    Finalize1();
  }
}

How can I save good code sturcture and solve code copying? Finalize1/2/3 is a API functions and not my program classes. Maybe some STL containers can solve it? Maybe something like that?

void GoodExample() {
  if (!Initialize1())
    return;
  RaiiWrapper<void(*)()> raii_wrapper1([]() {
    Finalize1();
  });

  if (!Initialize2())  {
    //Finalize1();
    return;
  }
  RaiiWrapper<void(*)()> raii_wrapper2([]() {
    Finalize2();
  });

  if (!Initialize3())  {
    //Finalize1();
    //Finalize2();
    return;
  }
  RaiiWrapper<void(*)()> raii_wrapper3([]() {
    Finalize3();
  });

  if (!Initialize4()) {
    //Finalize1();
    //Finalize2();
    //Finalize3();
    return;
  }
  RaiiWrapper<void(*)()> raii_wrapper4([]() {
    Finalize4();
  });

  // some code..

  //Finalize1();
  //Finalize2();
  //Finalize3();
  //Finalize4();
}

Solution

  • Why not use real objects?

    struct SetupPart1 {
       SetupPart1  () { if (!Initialize1() throw std::runtime_error("Part1"); }
       ~SetupPart1 () { Finalize1(); }
    };
    

    and so on for part 2, 3, 4, etc. Now your example looks like this:

    void GoodExample() {
        try {
            SetupPart1 p1;
            SetupPart2 p2;
            SetupPart3 p3;
            SetupPart4 p4;
    
         // some code ...
            }
        catch { const std::runtime_error &ex ) {
            std::cerr << "GoodExample Failed: " << ex.what << std::end;
            }
        }