我是否必须依赖编译器NRVO?

时间:2014-12-10 21:43:29

标签: c++ optimization compiler-optimization

我需要调用一个为我返回一个对象的函数。问题是该对象有一个析构函数,它可以在将函数输出分配到另一个对象之前破坏数据。 在我的程序中,我有一个运算符+,它添加了两个矩阵并返回两个矩阵的总和:

C=A+B

根据名称返回值优化(NRVO),以下代码不应立即调用析构函数:

Matrix operator+(const Matrix &m1, const Matrix &m2)
{
    Matrix sum;
    m1.clone(sum);
    for...
        for...
            sum.members[i][j]+=m2.members[i][j];
    return sum;
}

我的问题是我对信任NRVO没有信心,因为它取决于编译器。如果我将代码提供给其他人,他可能会编译代码并且他的编译器会给出不同的结果。

那么,有没有办法强制编译器给我我需要的内容,或者我必须将我的代码更改为不良形式,如下所示?

Matrix sum(Matrix &result, const Matrix &m1, const Matrix &m2)

修改

为了解释更多,我假设通过考虑NRVO,问题运行如下:

compiler reaches to C=A+B
operator + is called
object sum is created
object sum is calculated as sum of m1 and m2
sum is returned but its destructor is not called
the value of sum is directed to variable C
after function containing variable C reaches end, the destructor of C is called.

当没有应用NRVO时,我希望:

compiler reaches to C=A+B
operator + is called
object sum is created
object sum is calculated as sum of m1 and m2
sum is returned and its destructor is called which releases all data allocations
the return value of the operator+ is already destroyed so an invalid data is associated to variable C
...

1 个答案:

答案 0 :(得分:3)

  

问题是该对象有一个析构函数,它可以在将函数输出分配到另一个对象之前破坏数据。

这不是问题。对象将被正确复制,或者通过优化消除不必要的副本。如果您的副本ctor正确实现,最终结果将是相同的(当然,除了不太理想的代码)。如果对象副本非常昂贵,您可能应该使用写入语义上的副本,而实际的Matrix对象将是堆上创建的真实对象的瘦包装器。

未应用NRVO时会发生什么:

compiler reaches to C=A+B
operator + is called
object sum is created
object sum is calculated as sum of m1 and m2
temporary object of type Matrix created as a copy of object sum
object sum destroyed
temporary assigned to C

你可以看到最终结果是相同的,效果较差(创建临时对象)