内部函数调用后是否释放未使用的局部变量?

时间:2014-10-30 16:42:26

标签: c++ memory-management

我正在编写一个可以预处理数据并将其写入文件的应用程序。然后可以再次加载数据以在将来的运行中保存重新计算,但需要在进一步处理之前将其修改为通用格式。

如果没有预处理数据,该程序如下:

void no_preprocess(std::vector<T>& a)
{
    std::vector<P> b = hard_work(a);
    magic(a, b);
}

以及预处理数据:

void foo(std::vector<T>& a, std::string path)
{
    std::vector<D> c = read(path);
    std::vector<P> b = easy_work(a, c);
    // Is c now free?
    magic(a, b);
}

easy_work完成后,c永远不再使用。一旦c被调用,magic将会发生什么,即编译器是否足够聪明c

2 个答案:

答案 0 :(得分:3)

所有自动局部变量在超出范围时都会被销毁。调用c后,magic将在函数返回时自动销毁。

答案 1 :(得分:3)

当退出声明的范围时,对象将被立即销毁,而不是片刻之前。

编译器无法在“不再使用”的位置销毁本地,因为它们可能代表一个锁定句柄,需要保持活动状态并且活动直到块结束:

{
    std::lock_guard<std::mutex> guard(a_mutex);
    do_something_on_shared_structure();

    // guard is destructed here.
}

guard在其构造完成时“不再使用”,但编译器必须发出等待直到调用以下函数来破坏对象的代码,否则锁将过早释放。

编译器不允许尽早破坏对象,因为析构函数可能有副作用(在这种情况下释放锁)。

所以在你的情况下答案是相同的:c将在函数返回之前被破坏,这是在调用magic()之后,因为编译器没有不知道调用c的析构函数时会发生什么副作用。

如果您想提前破坏c,可以将read()的结果直接传递给easy_work()。这将导致构造一个临时向量作为easy_work()的第二个参数,它将在easy_work()返回后立即被销毁:

void foo(std::vector<T>& a, std::string path)
{
    std::vector<P> b = easy_work(a, read(path));

    magic(a, b);
}

(请注意,您无法将此简化为magic(a, easy_work(a, read(path))),因为read()返回的临时值将在magic()被调用时继续存在.C ++标准说临时存在时间很长作为它们出现的完整表达式,不再是,在这种情况下对magic()的调用将成为该表达式的一部分。)