【发布时间】:2012-03-07 15:54:35
【问题描述】:
我有一系列复杂的函数,它们执行非常相似的任务,只是函数中间有一个操作员。我的代码的简化版本可能是这样的:
#include <assert.h>
static void memopXor(char * buffer1, char * buffer2, char * res, unsigned n){
for (unsigned x = 0 ; x < n ; x++){
res[x] = buffer1[x] ^ buffer2[x];
}
};
static void memopPlus(char * buffer1, char * buffer2, char * res, unsigned n){
for (unsigned x = 0 ; x < n ; x++){
res[x] = buffer1[x] + buffer2[x];
}
};
static void memopMul(char * buffer1, char * buffer2, char * res, unsigned n){
for (unsigned x = 0 ; x < n ; x++){
res[x] = buffer1[x] * buffer2[x];
}
};
int main(int argc, char ** argv){
char b1[5] = {0, 1, 2, 3, 4};
char b2[5] = {0, 1, 2, 3, 4};
char res1[5] = {};
memopXor(b1, b2, res1, 5);
assert(res1[0] == 0);
assert(res1[1] == 0);
assert(res1[2] == 0);
assert(res1[3] == 0);
assert(res1[4] == 1);
char res2[5] = {};
memopPlus(b1, b2, res2, 5);
assert(res2[0] == 0);
assert(res2[1] == 2);
assert(res2[2] == 4);
assert(res2[3] == 6);
assert(res2[4] == 8);
char res3[5] = {};
memopMul(b1, b2, res3, 5);
assert(res3[0] == 0);
assert(res3[1] == 1);
assert(res3[2] == 4);
assert(res3[3] == 9);
assert(res3[4] == 16);
}
使用 C++ 模板来避免重复代码看起来是一个很好的案例,因此我一直在寻找一种方法来将我的代码更改为如下所示的内容(伪代码):
#include <assert.h>
template <FUNCTION>
void memop<FUNCTION>(char * buffer1, char * buffer2, char * res, size_t n){
for (size_t x = 0 ; x < n ; x++){
res[x] = FUNCTION(buffer1[x], buffer2[x]);
}
}
int main(int argc, char ** argv){
char b1[5] = {0, 1, 2, 3, 4};
char b2[5] = {0, 1, 2, 3, 4};
char res1[5] = {};
memop<operator^>(b1, b2, res1, 5);
assert(res1[0] == 0);
assert(res1[1] == 0);
assert(res1[2] == 0);
assert(res1[3] == 0);
assert(res1[4] == 0);
char res2[5] = {};
memop<operator+>(b1, b2, res2, 5);
assert(res2[0] == 0);
assert(res2[1] == 2);
assert(res2[2] == 4);
assert(res2[3] == 6);
assert(res2[4] == 8);
char res3[5] = {};
memop<operator*>(b1, b2, res3, 5);
assert(res3[0] == 0);
assert(res3[1] == 1);
assert(res3[2] == 4);
assert(res3[3] == 9);
assert(res3[4] == 16);
}
难点是我不愿意接受结果代码的任何减速。这意味着暗示间接调用(通过 vtable 或函数指针)的解决方案是不行的。
这个问题的常见 C++ 解决方案似乎是将要调用的运算符包装在仿函数类的 operator() 方法中。通常会得到类似下面的代码:
#include <assert.h>
template <typename Op>
void memop(char * buffer1, char * buffer2, char * res, unsigned n){
Op o;
for (unsigned x = 0 ; x < n ; x++){
res[x] = o(buffer1[x], buffer2[x]);
}
};
struct Xor
{
char operator()(char a, char b){
return a ^ b;
}
};
struct Plus
{
char operator()(char a, char b){
return a + b;
}
};
struct Mul
{
char operator()(char a, char b){
return a * b;
}
};
int main(int argc, char ** argv){
char b1[5] = {0, 1, 2, 3, 4};
char b2[5] = {0, 1, 2, 3, 4};
char res1[5] = {};
memop<Xor>(b1, b2, res1, 5);
assert(res1[0] == 0);
assert(res1[1] == 0);
assert(res1[2] == 0);
assert(res1[3] == 0);
assert(res1[4] == 0);
char res2[5] = {};
memop<Plus>(b1, b2, res2, 5);
assert(res2[0] == 0);
assert(res2[1] == 2);
assert(res2[2] == 4);
assert(res2[3] == 6);
assert(res2[4] == 8);
char res3[5] = {};
memop<Mul>(b1, b2, res3, 5);
assert(res3[0] == 0);
assert(res3[1] == 1);
assert(res3[2] == 4);
assert(res3[3] == 9);
assert(res3[4] == 16);
}
这样做有什么性能损失吗?
【问题讨论】:
-
只有您可以通过以下方式确定哪个在性能方面更好: 1. 分析 2. 比较和分析生成的汇编代码。这两个都在你的工作环境中。
-
仿函数可能会被内联。
-
如果您摆脱本地实例并将这些操作设为静态成员函数,编译器可能会更轻松地进行优化。然而,任何一种方式的代码都可以被优化掉(使用足够先进的编译器)。
-
@EthanSteinberg:正如我所展示的,这并不重要,只要函数调用是内联的,删除
this参数就是一个简单的死存储消除。