C++ 访问成员变量时的性能注意事项
我有一个数字处理程序,其中我要解的方程由不同类的成员函数表示。当然,每个类都有几个成员变量,这些变量是方程的输入。成员变量目前是double和int之类的原语,但是为了更好地与GUI集成,我想用托管变量替换原语;i、 我想使用一个单独的类来保存变量的名称和值,并处理读取和写入它的值。我关心代码的性能和可读性。例如,我宁愿看到像C++ 访问成员变量时的性能注意事项,c++,C++,我有一个数字处理程序,其中我要解的方程由不同类的成员函数表示。当然,每个类都有几个成员变量,这些变量是方程的输入。成员变量目前是double和int之类的原语,但是为了更好地与GUI集成,我想用托管变量替换原语;i、 我想使用一个单独的类来保存变量的名称和值,并处理读取和写入它的值。我关心代码的性能和可读性。例如,我宁愿看到像x=y+2这样看起来“自然”的代码,而不是x.set\u value(y.get\u value()+2) 我想出了四种不同的方法,并试验了每种方法所需的时间(代码如下)。
x=y+2
这样看起来“自然”的代码,而不是x.set\u value(y.get\u value()+2)
我想出了四种不同的方法,并试验了每种方法所需的时间(代码如下)。我用MSVC 2013编译了这个,使用的是调试版本。我在发布模式下得到了无意义的结果,因为我认为我的循环得到了优化。结果似乎意义重大;使用原语或直接访问成员变量需要使用getter/setter函数或cast运算符重载的一半时间
我的问题是:我是否适当地测试了这些不同的方法?有没有更好的方法来做我想做的事?谢谢
#include <iostream>
#include <chrono>
using namespace std;
using namespace std::chrono;
//Class to manage input parameters
struct Parameter {
double _value = 0.0;
double Get_value() const {return _value;}
void Set_value(double value) {_value = value;}
operator double(){return _value;}
void operator=(const double& rhs) {_value = rhs;}
};
int main() {
const size_t NUM_TESTS = 100; //Number of tests to run
const size_t MAX_ITER = 1000000; //Number of iterations to run in each test
const double x = 2.71828; //Variable to read from
double y = 0; //Variable to write to
Parameter test_parameter; //managed variable to read/write from/to
double test_primitive = 0.0; //primitive variable to read/write from/to
size_t t_primitive = 0; //Total time spent on primitive variable (microseconds)
size_t t_managed_cast = 0; //Time spent on managed variable using cast and assignment operators
size_t t_managed_getset = 0; //Time spent on managed variable using getter/setter functions;
size_t t_managed_direct = 0; //Time spent on managed variable using direct access of member var.
for (size_t n = 0; n < NUM_TESTS; ++n) {
//Test using a primitive variable.
auto t0 = high_resolution_clock::now();
for (size_t i = 0; i < MAX_ITER; ++i) {
test_primitive = x;
y = test_primitive;
}
auto t1 = high_resolution_clock::now();
t_primitive += duration_cast<microseconds>(t1-t0).count();
//Test using a managed variable, using cast operator and assignment operator
t0 = high_resolution_clock::now();
for (size_t i = 0; i < MAX_ITER; ++i) {
test_parameter = x;
y = test_parameter;
}
t1 = high_resolution_clock::now();
t_managed_cast += duration_cast<microseconds>(t1-t0).count();
//Test using managed variable, using getter/setter member functions
t0 = high_resolution_clock::now();
for (size_t i = 0; i < MAX_ITER; ++i) {
test_parameter.Set_value(x);
y = test_parameter.Get_value();
}
t1 = high_resolution_clock::now();
t_managed_getset += duration_cast<microseconds>(t1-t0).count();
//Test using managed variable, using direct public access
t0 = high_resolution_clock::now();
for (size_t i = 0; i < MAX_ITER; ++i) {
test_parameter._value = x;
y = test_parameter._value;
}
t1 = high_resolution_clock::now();
t_managed_direct += duration_cast<microseconds>(t1-t0).count();
}
cout << "Average time for primitive (microseconds): " << t_primitive / NUM_TESTS << endl;
cout << "Average time for managed with cast (microseconds): " << t_managed_cast / NUM_TESTS << endl;
cout << "Average time for managed with get/set (microseconds): " << t_managed_getset / NUM_TESTS << endl;
cout << "Average time for managed with direct access (microseconds): " << t_managed_direct / NUM_TESTS << endl;
return 0;
}
#包括
#包括
使用名称空间std;
使用名称空间std::chrono;
//类来管理输入参数
结构参数{
双_值=0.0;
双Get_value()常量{return_value;}
无效设置值(双值){u值=值;}
运算符double(){return_value;}
void运算符=(constdouble&rhs){u值=rhs;}
};
int main(){
const size\u t NUM\u TESTS=100;//要运行的测试数
const size\u t MAX\u ITER=1000000;//每次测试中要运行的迭代次数
const double x=2.71828;//要从中读取的变量
双y=0;//要写入的变量
参数test_Parameter;//要从/写入的托管变量
double test_primitive=0.0;//要从/写入的原语变量
size\u t\u primitive=0;//花费在primitive变量上的总时间(微秒)
size\u t\u managed\u cast=0;//使用cast和赋值运算符在托管变量上花费的时间
size\u t\u managed\u getset=0;//使用getter/setter函数在托管变量上花费的时间;
size\u t\u managed\u direct=0;//使用成员变量的直接访问在托管变量上花费的时间。
对于(大小n=0;n
现在再次启用优化,只需担心启用优化后的时间安排
在这里,我修正了你的基准
现在再次启用优化,只需担心启用优化后的计时问题。调试版本不会内联这些访问器方法,因此需要更长的时间。发布版本不会出现此问题
尝试使用发布版本,但将变量设置为volatile,我相信这将禁用循环优化。调试版本不会内联这些访问器方法,因此需要更长的时间。发布版本不会有此问题
尝试使用发布版本,但将变量设置为volatile,我相信这会禁用循环优化。我认为我的循环会得到优化…请看:您的直觉是正确的,调用函数会有开销。如果您真的关心性能,直接访问和修改成员变量会很快但是请注意,getter和setter,尤其是,几乎所有的compilers@Cyber:运行时函数调用有开销,但源代码中的函数调用并不意味着运行时调用。这毕竟是内联点。处理无意义基准测试结果的正确方法s不是禁用优化,而是修复基准测试。如果这些调用在您实际要运行的编译代码中最终存在(我必须假设这些调用不是调试代码),则可能会产生开销.Non-virtual const getter很容易成为编译器进行的最频繁的内联优化之一。请修复您发布的代码,使其有意义并正确地工作。@BenVoigt我同意,并且无意提出其他建议(如果我这么做了!)。如果你关心优化代码的性能,你应该对照优化代码进行评测,这是毫无疑问的。我认为我的循环得到了优化…请看:你的直觉是正确的,调用fun会有开销
volatile const double x = 2.71828;
volatile double y = 0;
// ^^ VERY IMPORTANT