C ++自动完成或对象销毁

问题描述

在此示例中,我遇到了复制代码的问题:

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();
}

这里是错误代码结构。如果我有很多构造,那么代码的宽度将太大,这也是不好的:

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

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

如何保存良好的代码结构并解决代码复制问题? Finalize1 / 2/3是API函数,而不是我的程序类。 也许某些STL容器可以解决它? 也许是这样吗?

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();
}

解决方法

为什么不使用真实物体?

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

,对于第2、3、4等部分,依此类推。 现在您的示例如下所示:

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

您可以简化Marshall的建议,并使用尚未标准化的std::make_unique_resource()(此功能与scope_guard紧密相关,这是几年前Andrei Alexandrescu以及该建议中提出的一种装置)。这样可以为您提供一个具有两个功能的对象-一个在变量作用域的开始运行,另一个在其作用域结束(即分别在构造和破坏时)运行。

然后,您无需编写四个单独的类,而只需编写:

void GoodExample() {
    auto r1 = std::make_unique_resource(Initialize1,Finalize1);
    auto r2 = std::make_unique_resource(Initialize2,Finalize2);
    auto r3 = std::make_unique_resource(Initialize3,Finalize3);
    auto r4 = std::make_unique_resource(Initialize4,Finalize4);

    // some code
}

该提案具有实施代码; -一点也不复杂。因此,您只需复制实现并创建自己的not_std::make_unique_resource()函数和相关的模板化类即可。

,

每当从API获得宝贵的资源时,都需要使用适当的析构函数将其包装为对象。因此,如果Initialize1初始化something1,那么something1实际上应该是知道如何初始化以及如何完成自身的对象Something1。另外,初始化失败会引发异常(fstream不会这样做,因为fstream比该概念还旧。)

class Something1 {
public: Something1 () { if (!Initialize1()) throw resource_failed ("1"); }
~Something1 () { Finalize1(); }
}

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...