使用析构函数做工作
Use the destructor to do work
我有一个包含一组请求的 class 事务。
每X秒设置当前事务中的请求,并清除请求列表。
是否可以将 class 事务设计为在析构函数销毁期间发送事务中的请求?
这意味着我们分配一个新的事务,只要它还活着,就向它添加新的请求,一旦调用析构函数,所有的请求都会被发送。
这样我们可以保证:
- 发送所有交易(只要我们不泄露交易对象)。
- 交易发送后无法添加更改。
这被认为是一种好的做法吗?或者使用 SendRequests 方法发送所有请求并清除列表会更好吗?
析构函数在 C++ 语言中只有一个用途。那就是根据 RAII 管理(因此它可以记录、使用辅助对象或函数,等)释放在构造函数中获取的资源。任何其他用途迟早会给您带来麻烦。
你通常会做恰恰相反的事情——对积极分支(导致提交的分支)明确,但回滚分支 RAII-based 以保证一致的 commit-or-rollback 行为。主要是因为从析构函数中抛出存在问题,并且实施 no-throw 回滚通常比对提交执行相同的回滚更容易。
您应该只在 class.
的析构函数中执行实际解构手头对象的操作
析构函数仅用于 clean-up 任务 仅与当前对象有关 。在这种对象的end-of-life周期触发对外通信,肯定会给你带来麻烦。
一个示例问题发生在子classing 和多态性过程中:
#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;
}
这导致输出
Construct A
Construct B
Actual worker function in B
Deconstruct B
Deconstruct A
Dummy virtual worker function in A
因此,当您子class 您的 class 并覆盖其中的虚函数时,当您到达基础 class 的析构函数时,您将失去被覆盖的功能。在示例中,当在 A
的析构函数中调用 this->doWork()
时会发生这种情况。
这可能会弄乱您的数据、流程或您 class 正在做的任何事情。因此,我再次建议不要在析构函数中触发实际工作。最好在 class 中为此定义一个单独的函数,并在为此特定任务指定的时间调用它。否则你的代码只会失去很多可读性和可维护性。
一方面,技术可能性:
12.7/4: Member functions, including virtual functions, can be called during construction or destruction.
另一方面,每一个设计都应该尊重的指导原则:
12.4/15 Once a destructor is invoked for an object, the object no longer exists;
因此我不建议这样的设计。
这样的设计是不好的做法。如果创建了一个事务,并向其中添加了一些请求,如果出于任何原因需要中断事务(连接的系统消失,用户想要中断,发生异常等),您的设计将强制要执行的不完整请求。这不符合人们对交易的全部或全部期望的逻辑。
更好的方法是根据 state design pattern 设计您的交易:例如,交易将具有以下状态:
- 已创建(新的,无请求),
- 正在进行(正在添加请求),
- to-be-executed(不会执行额外的请求),
- 并已完成(请求已执行)或已取消。
如果调用了析构函数,状态既没有完成也没有取消,析构函数应该争取取消。
我有一个包含一组请求的 class 事务。 每X秒设置当前事务中的请求,并清除请求列表。
是否可以将 class 事务设计为在析构函数销毁期间发送事务中的请求?
这意味着我们分配一个新的事务,只要它还活着,就向它添加新的请求,一旦调用析构函数,所有的请求都会被发送。
这样我们可以保证:
- 发送所有交易(只要我们不泄露交易对象)。
- 交易发送后无法添加更改。
这被认为是一种好的做法吗?或者使用 SendRequests 方法发送所有请求并清除列表会更好吗?
析构函数在 C++ 语言中只有一个用途。那就是根据 RAII 管理(因此它可以记录、使用辅助对象或函数,等)释放在构造函数中获取的资源。任何其他用途迟早会给您带来麻烦。
你通常会做恰恰相反的事情——对积极分支(导致提交的分支)明确,但回滚分支 RAII-based 以保证一致的 commit-or-rollback 行为。主要是因为从析构函数中抛出存在问题,并且实施 no-throw 回滚通常比对提交执行相同的回滚更容易。
您应该只在 class.
的析构函数中执行实际解构手头对象的操作析构函数仅用于 clean-up 任务 仅与当前对象有关 。在这种对象的end-of-life周期触发对外通信,肯定会给你带来麻烦。
一个示例问题发生在子classing 和多态性过程中:
#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;
}
这导致输出
Construct A
Construct B
Actual worker function in B
Deconstruct B
Deconstruct A
Dummy virtual worker function in A
因此,当您子class 您的 class 并覆盖其中的虚函数时,当您到达基础 class 的析构函数时,您将失去被覆盖的功能。在示例中,当在 A
的析构函数中调用 this->doWork()
时会发生这种情况。
这可能会弄乱您的数据、流程或您 class 正在做的任何事情。因此,我再次建议不要在析构函数中触发实际工作。最好在 class 中为此定义一个单独的函数,并在为此特定任务指定的时间调用它。否则你的代码只会失去很多可读性和可维护性。
一方面,技术可能性:
12.7/4: Member functions, including virtual functions, can be called during construction or destruction.
另一方面,每一个设计都应该尊重的指导原则:
12.4/15 Once a destructor is invoked for an object, the object no longer exists;
因此我不建议这样的设计。
这样的设计是不好的做法。如果创建了一个事务,并向其中添加了一些请求,如果出于任何原因需要中断事务(连接的系统消失,用户想要中断,发生异常等),您的设计将强制要执行的不完整请求。这不符合人们对交易的全部或全部期望的逻辑。
更好的方法是根据 state design pattern 设计您的交易:例如,交易将具有以下状态:
- 已创建(新的,无请求),
- 正在进行(正在添加请求),
- to-be-executed(不会执行额外的请求),
- 并已完成(请求已执行)或已取消。
如果调用了析构函数,状态既没有完成也没有取消,析构函数应该争取取消。