强制清除临时变量

时间:2018-03-10 16:32:24

标签: c++ memory temporary-objects

(请原谅我这个问题是否重复,我是初学者,不知道要搜索哪些条款才能找到答案!)

我正在尝试为c ++编写一个带有一些非常基本的内存管理的线性代数库 - 主要是使用shared_ptrs;一旦ptr计数达到0,它就会将内存返回给管理器。 我正在处理的数组的大小非常大,而且内存非常宝贵,所以我试图强制代码尽快触发清理冗余内存变量。

考虑:

a,b,c,d,e不是临时变量,每个约5GB。

z = a + b + c + d + e

或者

z = add(a,add(b,add(c,add(d,e)))) - 这就是我到目前为止实际编码的方式,没有操作符过载。

我发现一旦相等操作完成,临时变量(每个操作一个)只会超出范围,因此shared_ptr仍然认为内存正在使用中。结果,刮擦空间的清理一下子发生,理论上,单个存储器块保持在&#d; d + e'可能会被扔掉一次&#c; c + d + e'存储,等等。

显然这会导致内存使用量大幅增加,因为在使用的临时空间中不是5GB,而是需要20GB。

要解决这个问题,我必须做以下事情

z = d + e

z = c + z

z = b + z

z = a + z

这允许先前的临时变量超出每个新行的范围,但它会在我的代码的几个部分中引起一些非常讨厌的膨胀。

有没有办法强制代码在行尾之前将临时内存返回给管理器?我认为我可以对共享指针做些什么,或者通过引用而不是值传递,但我不能完全指责它。

澄清一下,我在寻找什么:

为(d + e)分配内存,执行计算

为(c + d + e)分配内存,执行计算,释放(d + e)

为(b + c + d + e)分配内存,执行计算,释放(c + d + e)

为(a + b + c + d + e)分配内存,执行计算,释放(b + c + d + e)

将(a + b + c + d + e)指针指向z

#include <iostream>

class Foo {
public:
    int fooid;
    Foo(int fi) {
        fooid = fi;
        std::cout << "Creating array " << fooid << std::endl;
    }
    ~Foo() {
        std::cout << "Cleanup array " << fooid << std::endl;
    }
};

Foo mult(const Foo &a, const Foo &b)
{
    //std::cout << "Constructing new foo" << std::endl;
    Foo out(a.fooid*b.fooid);
    return out;
}


int main()
{
    Foo twos(2); //placeholders for huge non-temporary arrays
    Foo threes(3);
    Foo fives(5);
    Foo sevens(7);
    Foo elevens(11);
    std::cout <<"Method 1" << std::endl;
    Foo vx = mult(mult(mult(mult(twos,threes), fives),sevens),elevens);
    //std::cout << vx.fooid << std::endl;
    //system("pause");

    std::cout << std::endl <<"Method 2" << std::endl;
    //Alternative, over 3 lines, forces destructors earlier than above, more scratch space for the later operations
    //Note array 30 is deleted before array 210 is constructed, unlike Method 1
    Foo vx1 = mult(twos, threes);
    vx1 = mult(vx1, fives);
    vx1 = mult(vx1, sevens);
    vx1 = mult(vx1, elevens);

    std::cout << std::endl <<"End" << std::endl;
    return 0;
}

输出如下:

Creating array 2
Creating array 3
Creating array 5
Creating array 7
Creating array 11
Method 1
Creating array 6
Creating array 30
Creating array 210
Creating array 2310
Cleanup array 210
Cleanup array 30
Cleanup array 6

Method 2
Creating array 6
Creating array 30
Cleanup array 30
Creating array 210
Cleanup array 210
Creating array 2310
Cleanup array 2310

End
Cleanup array 2310
Cleanup array 2310
Cleanup array 11
Cleanup array 7
Cleanup array 5
Cleanup array 3
Cleanup array 2

上述方法之间的主要区别在于方法2能够在执行下一步计算之前释放旧的临时变量,而第一种方法在计算完全完成之前保留其所有内存。我希望找到一种方法,我可以获得方法2的结果,同时按照方法1的方式进行编码。

很抱歉经常编辑。想要做对。

2 个答案:

答案 0 :(得分:0)

简单的答案,从C ++ 11开始(至少部分由之前的优秀编译器实现)是通过 value 接受你的参数。这似乎违反直觉,因为它听起来像更多副本,但实际上现有数据的所有权通过移动构造函数(和/或编译器魔术)传递到函数中。

然后,您更新“到位”的“副本”并将其返回,以便将其资源转移到另一个函数调用中以便重复使用/更新再次。在完整表达式结束时,将运行几个析构函数(由于“强制copy elision”,每个函数返回时,C ++ 17 可能运行它们,但大多数将用于移动 - 来自资源已经被重用和/或释放的对象。

当然,等大小参数的每个函数最多需要一个来存储其结果;由于大多数运算符都是左关联的,因此by-value参数的明显选择是第一个。您可以使用值传递的第二个操作数定义减法的变量,以捕获z=a-(b*c)等案例。

答案 1 :(得分:0)

  

我正在尝试编写一个线性代数库,其中包含一些   C ++的基本内存管理-基本上使用shared_ptrs;   一旦ptr计数达到0,它将把内存返回给管理器。

     

...

     

a,b,c,d,e不是临时变量,每个〜5GB。

如果您要创建a linear algebra library来练习编程技能,那就好。
但是您已经写过variables, ~5GB each了!这意味着您正在解决一些严重的问题。如果您是我,则可以使用现成的库gmp。原因很简单。这个库由许多聪明的人创建和优化了数千个小时。这样,您可以从“等式”中消除一个问题。

矩阵的大小非常大,建议您应该阅读的另一件事是sparse matrix。这样做可能会使您的数据更紧凑,并加快计算速度。

当您使用库时,清除已使用的变量的内存将非常简单(调用一些名为clean之类的函数)。这样您的问题就不会成为问题。

我怀疑您的问题是XY problem,请考虑提供更多不那么笼统的信息