我写了一些伪代码,可以解释我在实际应用中发现的问题(Arduino 1.6 - https://github.com/maciejmiklas/LEDDisplay):
Display.h:
class Display {
public:
void testRef();
void testVal();
private:
typedef struct {
uint8_t xOnFirstKit;
uint8_t yOnFirstKit;
uint8_t xRelKit;
uint8_t yRelKit;
uint8_t xRelKitSize;
uint8_t yRelKitSize;
uint8_t xDataBytes;
uint8_t xKit;
uint8_t yKit;
uint8_t xOnKit;
uint8_t yOnKit;
uint8_t xOnKitSize;
uint8_t yOnKitSize;
uint8_t xOnScreenIdx;
uint8_t yOnScreenIdx;
uint8_t yDataIdx;
} KitData;
inline void paintOnKitRef(KitData *kd);
inline void paintOnKitVal(KitData kd);
}
Display.cpp:
#include "Display.h"
void Display::testRef(){
KitData *kd = ....
for(int i = 0 ; i < 5000 ; i++){
paintOnKitRef(kd);
....
}
}
void Display::testVal(){
KitData *kd = ....
for(int i = 0 ; i < 5000 ; i++){
paintOnKitVal(*kd);
....
}
}
inline void Display::paintOnKitRef(KitData *kd){
for(int i = 0 ; i < 100 ; i++){
kd->yDataIdx++;
kd->yOnScreenIdx++;
.....
}
}
inline void Display::paintOnKitVal(KitData kd){
for(int i = 0 ; i < 100 ; i++){
kd.yDataIdx++;
kd.yOnScreenIdx++;
.....
}
}
我有结构:KitData
大于16个字节,所以我决定用指针而不是值传递它 - 它按预期工作。
我已经测量了执行时间,看起来像传递值(testVal()
)比通过引用(testRef()
)传递快30%。
这是正常的吗?
修改
上面的代码只是一个伪代码 - 在我的实际测试方法中:paintOnKitVal()
和paintOnKitRef()
包含执行许多操作和其他方法的实际代码。这两种方法也做同样的事情 - 唯一的区别是访问kd
(通过指针或点表示法)。
这是真正的测试类:https://github.com/maciejmiklas/LEDDisplay/blob/callByPoint/Display.cpp
paint(...)
- 这将使用第211行中的call-by-pointer 答案 0 :(得分:5)
这部分代码绝对没有任何内容,优化器会认识到:
inline void Display::paintOnKitVal(KitData kd){
for(int i = 0 ; i < 100 ; i++){
kd.yDataIdx++;
kd.yOnScreenIdx++;
}
}
您认为您测试了传递值的性能。但是你真的测试了编译器识别代码什么都不做的事实的能力。
当您通过指针(C程序员可能通过引用调用“但C ++程序员不会”通过引用“)时,单独的函数不能说什么都不做。优化器需要更广泛地理解检测缺乏效果的整个程序。
答案 1 :(得分:3)
传递通过值:
void foo(int a) {
a = 30; // passed in param is now 30 until end of scope
}
int main() {
int b = 3;
foo(b); // copy of b is made, copy is assigned value 30
// b is still 3
}
传递通过引用:
void foo(int& a) {
a = 30; // passed in param is now 30 because a reference was passed in
}
int main() {
int b = 3;
foo(b); // reference to b is assigned value 30
// b is now 30
}
传递指针类似以传递引用,但有一些差异outlined here。
您为testVal
撰写的代码将在kd
的副本上执行操作。这不是你想要的。
对于小结构,传递值和传递引用的速度将类似。 然而,内存占用量将大不相同。每次传递内容时,按值传递都会复制,这将占用大量内存。
There are likely optimizations因为正在制作副本而不是对编译器为您制作的传入对象的实际更改。但是,这是以错误算法为代价的。
在传递值后,更改将不会反映在传入的kd
中。指针&#39;变化将反映出来并且是正确的。