C++ 在C+中检测编译时的重复工作+;代码 让我们考虑下面的代码: struct Foo { Foo(Bar b1, Bar b2) : b1(b1), b2(b2) {} void work() { b1.work(); b2.work(); //something } Bar& b1; Bar& b2; }; struct Bar { void work() { /* something */ } }; int main() { Bar a, b; a.work(); //something... Foo c(a,b); c.work(); //something... }
按照我编写(或打算编写)的方式,a.work()将执行两次。但是,让我们假设,我,正如程序员所知道的,执行它两次是对执行时间的浪费,让我们假设这是一个更复杂的软件的一部分,在这个软件中,手动跟踪哪些工作是完成的,哪些工作没有完成太麻烦了 显然,我可以在Bar中存储一些布尔标志,每次都检查工作是否已经完成,但我想知道,是否有某种方法可以在编译时捕捉到它。因为在编译时,已经很清楚工作已经完成了。不,不太清楚 编译器能够进行一些静态分析,如果您可以要求它诊断这种情况,在一些简单的情况下,它可能能够这样做。但是一旦你有了一个非平凡的流程(例如,运行时C++ 在C+中检测编译时的重复工作+;代码 让我们考虑下面的代码: struct Foo { Foo(Bar b1, Bar b2) : b1(b1), b2(b2) {} void work() { b1.work(); b2.work(); //something } Bar& b1; Bar& b2; }; struct Bar { void work() { /* something */ } }; int main() { Bar a, b; a.work(); //something... Foo c(a,b); c.work(); //something... },c++,metaprogramming,C++,Metaprogramming,按照我编写(或打算编写)的方式,a.work()将执行两次。但是,让我们假设,我,正如程序员所知道的,执行它两次是对执行时间的浪费,让我们假设这是一个更复杂的软件的一部分,在这个软件中,手动跟踪哪些工作是完成的,哪些工作没有完成太麻烦了 显然,我可以在Bar中存储一些布尔标志,每次都检查工作是否已经完成,但我想知道,是否有某种方法可以在编译时捕捉到它。因为在编译时,已经很清楚工作已经完成了。不,不太清楚 编译器能够进行一些静态分析,如果您可以要求它诊断这种情况,在一些简单的情况下,它可能能够这样
if
条件),它就会很快离开窗口。这可能是没有人为编译器创建这样一个可编程特性的部分原因:高复杂性,可忽略不计的实用性
也许可以对一些第三方静态分析仪进行编程(或创建一个!)来诊断您的简单案例,但同样,对于处理您已经可以用眼睛发现的最琐碎的案例来说,这需要大量的工作
相反,您可以使work()
发生在Bar
构造函数中。那么在同一物体上做两次功是不可能的。然而,在一个构造器中执行大量的工作通常是不受欢迎的
我确实会在栏中保留一个状态标志
,并通过相应地维护该标志的值,从后续的工作()返回false
。作为奖励,在返回false
之前,在函数中粘贴一个断言,以便在测试过程中捕获违规行为
州标志不必是布尔值;它可以是枚举
。对象中的健壮状态机非常有用
话虽如此,我还是建议您重新审视当前的方法,将对事物的引用传递给对它们起作用的其他事物;这不是一个容易遵循的设计,这只是一个简单的例子,你的设计!您可能希望考虑传递一些单用代理类型。 实际上,在编译时,代码是否执行并不明显。假设您有一个if语句,并在其中调用a.work()
。编译器如何知道当时是否执行了a.work()
?正如您所说,不要认为if
语句非常简单(假设它正在寻找某个外部信号并根据该信号执行代码)。避免这种行为的最好方法是保持布尔值。另一种方法。在条
对象中有一个函数指针,并在work()
函数中调用指针
。在构造函数中,将指针定义为实际的功函数。在函数末尾,将指针重新指定为空函数
在这种情况下,第一次执行将完成任务。但是以后的执行将不起任何作用(也不检查布尔值
标志)
类似上面的内容。肮脏的方式:预处理器宏定义在work()内部。
:#如果ndef已经完成#定义已经完成(…例程)#endif
@Suthiro如何工作?这是预处理器。@asterswithwings经过再三考虑后,你是对的-它不会,但我认为它可以通过预处理器实现。@Suthiro我不知道你是想诊断/发现第二个呼叫,还是只是默默地将其设为不操作?您的要求是什么?这实际上是一个好主意(假设OP不需要诊断第二个呼叫,只需将其设置为无OP)。虽然它基本上与bool
的思想相同,只是添加了间接寻址,但您可能是对的,但是在boolean
情况下,程序每次都会检查布尔值。我知道,检查并不是最糟糕的操作,而且非常琐碎。但是如果问题是不再需要做更多的操作,我认为这是一个很好的例子。谢谢你的想法。但是,如果编译器认为这是合理的,那么编译器就不可能内联实际工作了吗?如果是这样的话,我会更倾向于你的另一个答案,即我应该使用布尔值。正如我在运行时所猜测的,不可能使函数以内联方式编译。如果要将其编译为内联函数,布尔值是解决方案,但如果不需要内联,两者都适用。@arsdever我认为检查bool
比取消引用指针来调用函数便宜。此外,使用bool
,您可以用它做其他事情,而如果您想检查“函数是否为空?”则不能检查。但我们都在扯淡;)
struct Bar {
typedef void (*Bar::fptr_t)();
Bar() : fptr(actual_work) {}
void actual_work() {
/*something*/;
fptr = &Bar::empty_work;
}
void empty_work() {}
void work() {fptr();}
fptr_t fptr;
};