简体   繁体   English

临时对象在 C++ 中是不可避免的吗?

[英]Are temporary objects unavoidable in C++?

We read about different instances in C++ where temporary objects are created in code.我们阅读了 C++ 中在代码中创建临时对象的不同实例。 See for example .参见示例 Now, consider the following snippet of code.现在,考虑以下代码片段。

const int rows{250};
const int cols{250};
const double k{0.75};

double A[rows][cols];
double B[rows][cols];
double C[rows][cols];

// Code that initialises A and B
...

for (int i{}; i<rows; ++i) {
    for (int j{}; j<cols; ++j) {
        C[i][j] = k*A[i][j]*B[i][j]/(A[i][j]*A[i][j] + B[i][j]*B[i][j]);
    }
}

Are temporaries created when evaluating the numerator and denominator in the RHS of the equation in the inner for loop?在内部 for 循环中计算方程的 RHS 中的分子和分母时是否创建了临时变量? Obviously, one can evaluate the expression in parts and store the results in intermediate variables as below.显然,可以分部分计算表达式并将结果存储在中间变量中,如下所示。

for (int i{}; i<rows; ++i) {
    for (int j{}; j<cols; ++j) {
        double temp1 = A[i][j]*B[i][j];
        double temp2 = k*temp1;
        double temp3 = A[i][j]*A[i][j];
        double temp4 = B[i][j]*B[i][j];
        double temp5 = temp3 + temp4;
        C[i][j] = temp2/temp5;
    }
}

Doesn't the latter approach introduce additional computational steps and therefore more overhead for the inner for loop?后一种方法是否会引入额外的计算步骤,从而为内部 for 循环带来更多开销?

Replace the word 'temporary' with the word 'register' ;)将“临时”一词替换为“注册”一词;)

In general the first step in the compilation process is that the compiler will canonicalize ( https://en.wikipedia.org/wiki/Canonicalization ) the code so that it takes a standardised form.一般来说,编译过程的第一步是编译器将规范化 ( https://en.wikipedia.org/wiki/Canonicalization ) 代码,使其采用标准化形式。 It doesn't really matter how you format your code, or whether use temps or not, the compiler will re-arrange the code in both cases to be more or less identical.无论您如何格式化代码,或者是否使用临时文件,编译器都会重新排列两种情况下的代码,使其大致相同。 Chances are, it will end up generating something along these lines for both versions of your code:很有可能,它最终会为您的两个版本的代码生成以下内容:


        double temp1 = A[i][j]*B[i][j];
        double temp2 = k*temp1;
        double temp3 = A[i][j]*A[i][j];
        double temp4 = B[i][j]*B[i][j];
        double temp5 = temp3 + temp4;
        C[i][j] = temp2/temp5;

From there, the canonized form will be converted into assembly.从那里,规范化的形式将被转换为汇编。 In psuedo-code, this is roughly along the lines of the assembly that a compiler for x64 might generate:在伪代码中,这与 x64 编译器可能生成的程序集大致相同:

        xmm0 = load(B[i][j])
        xmm1 = load(A[i][j])
        xmm2 = xmm0 * xmm1;  // A[i][j]*B[i][j];
        xmm3 = load(k)
        xmm3 = xmm3 * xmm2;  // k*temp1;
        xmm1 = xmm1 * xmm1;  // A[i][j]*A[i][j];
        xmm0 = xmm0 * xmm0;  // B[i][j]*B[i][j];
        xmm0 = xmm1 + xmm0   // temp3 + temp4;
        xmm0 = xmm3 / xmm0   // temp2 / temp5;
        store(C[i][j], xmm0)

Pretty much every compiler will attempt to minimise the number of loads and stores (for they can be very expensive - eg cache misses, false sharing, etc) , and the rest of the temps will be stored as registers (assuming you don't run out!) .几乎每个编译器都会尝试最小化加载和存储的数量(因为它们可能非常昂贵 - 例如缓存未命中、错误共享等) ,其余的临时值将存储为寄存器(假设您不运行出来!)

If you have a relatively complex object, then you'd probably want to ensure you avoiding making temporary copies of the object.如果您有一个相对复杂的对象,那么您可能希望确保避免制作该对象的临时副本。 Even then, so long as the copy-constructor doesn't have side effects outside of the class, there is a good chance the compiler will elide those copies (eg return value optimisation).即便如此,只要复制构造函数在类之外没有副作用,编译器很有可能会忽略这些副本(例如返回值优化)。

Basically it's not something you really need to worry about.基本上这不是你真正需要担心的事情。 The compiler will pretty much ignore you anyway, rearrange your code as it sees fit, and generate resulting assembly that is as good as it can.无论如何,编译器几乎都会忽略您,按照它认为合适的方式重新排列您的代码,并生成尽可能好的结果程序集。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM