C++ 使用析构函数进行工作

C++ 使用析构函数进行工作,c++,raii,object-oriented-analysis,C++,Raii,Object Oriented Analysis,我有一个类事务,它保存一组请求。 每X秒设置一次当前事务中的请求,并清除请求列表 类事务的设计方式是否可以使其在销毁期间由析构函数发送事务中的请求 这意味着我们分配一个新的事务,只要它还活着,就向它添加新的请求,一旦调用析构函数,所有请求都将被发送 这样,我们可以保证: 发送所有事务(只要不泄漏事务对象) 无法在事务发送后向其添加更改 这被认为是一种良好的做法吗?还是更好地使用SeNeRebug方法发送所有请求并清除列表?< P>析构函数在C++语言中只有一个目的。也就是说,根据RAII管理(以

我有一个类事务,它保存一组请求。 每X秒设置一次当前事务中的请求,并清除请求列表

类事务的设计方式是否可以使其在销毁期间由析构函数发送事务中的请求

这意味着我们分配一个新的事务,只要它还活着,就向它添加新的请求,一旦调用析构函数,所有请求都将被发送

这样,我们可以保证:

  • 发送所有事务(只要不泄漏事务对象)
  • 无法在事务发送后向其添加更改

  • 这被认为是一种良好的做法吗?还是更好地使用SeNeRebug方法发送所有请求并清除列表?

    < P>析构函数在C++语言中只有一个目的。也就是说,根据RAII管理(以便它可以记录、使用助手对象或函数等)构造函数中获取的资源的释放。任何其他用途迟早会给您带来麻烦。

    您通常会做完全相反的事情——明确表示正分支(导致提交的分支),但使用基于RAII的回滚分支来保证一致的提交或回滚行为。主要是因为从析构函数中抛出存在问题,并且实现无抛出回滚通常比对提交执行相同操作要容易。

    您应该只执行在类的析构函数中实际解构手头对象的操作

    析构函数仅用于与当前对象相关的清理任务。在此类对象生命周期结束时触发外部通信肯定会给您带来麻烦

    在子类化和多态性期间出现一个示例问题:

    #include <iostream>
    
    class A {
    public:
      A() {
        std::cout << "Construct A" << std::endl;
      }
    
      virtual ~A() {
        std::cout << "Deconstruct A" << std::endl;
        this->doWork();
      }
    
      virtual void doWork() {
        std::cout << "Dummy virtual worker function in A" << std::endl;
      }
    };
    
    class B : public A {
    public:
      B() {
        std::cout << "Construct B" << std::endl;
      }
    
      virtual ~B() {
        std::cout << "Deconstruct B" << std::endl;
      }
    
      void doWork() {
        std::cout << "Actual worker function in B" << std::endl;
      };
    };
    
    int main(int argc, char** argv) {
      A* aTest = new B();
      aTest->doWork();
    
      delete aTest;
    
      return 0;
    }
    
    因此,当您对类进行子类化并重写其中的虚拟函数时,当您到达基类的析构函数时,您将丢失被重写的功能。在本例中,当在
    A
    的析构函数中调用
    this->doWork()
    时,就会发生这种情况


    这可能会弄乱您的数据、进程或您的类正在做的任何事情。所以,再一次,我建议不要触发析构函数中的实际功。最好在类中为此定义一个单独的函数,并在指定用于此特定任务的时间调用它。否则,您的代码只会失去很多可读性和可维护性。

    一方面,技术可能性:

    12.7/4:成员函数,包括虚拟函数,可以在构造或销毁期间调用

    另一方面,每个设计都应尊重的指导原则:

    12.4/15一旦为某个对象调用析构函数,该对象就不再存在

    因此,我不建议这样的设计

    这样的设计是不可取的。如果创建了一个事务,并向其添加了一些请求,如果出于任何原因需要中断该事务(连接的系统被禁用、用户想要中断、发生异常等),您的设计将强制执行未完成的请求。这不符合人们期望从事务中得到的逻辑

    更好的方法是根据设计事务:例如,事务将具有以下状态:

    • 已创建(新建,无请求)
    • 正在进行(正在添加请求)
    • 待执行(不执行其他请求)
    • 并已完成(请求已执行)或取消

    如果调用析构函数且状态未完成或未取消,析构函数应努力取消

    “可以这样设计类事务吗?在事务被析构函数销毁的过程中,它会发送事务中的请求吗?”不-你为什么会这样想?这是一个糟糕的想法。想象一下,当您启动一个事务时,在其中执行一些必要的操作,就会抛出一些东西。你的析构函数被调用并犯下一个不完整的错误…这就是我所想的。谢谢除非您非常了解标准,并且可以将此工具用于其他目的(如基准测试、计数等),否则就不会有任何问题。@bobah为什么不使用模板包装器来完成这项工作,而不是污染dtor?这样你就可以保持它的通用性。无论你多么认为“你很了解标准”,这些诡计都会很容易让你陷入麻烦。@PaulEvans-RAII基于工具的工具通常更容易考虑重用。包装器只在C++14中变成了“零开销”,在C++14中,完美的参数和返回值转发是可能的。@bobah很好,我同意有时我们必须妥协。但我说的是最佳实践。
    Construct A
    Construct B
    Actual worker function in B
    Deconstruct B
    Deconstruct A
    Dummy virtual worker function in A