何时被“替换”的变量不再可寻址

时间:2014-04-28 17:31:45

标签: c++ c++11 destructor

如果我为旧变量分配一个新变量,旧变量不再可寻址,但是我不确定它何时超出范围:

例如:

std::vector<int> foo() {
    return std::vector<int>{3,4,5};
}

int main() {

    std::vector<int> v{1,2,3};

    v = foo();  //when is the first vectors destructor called? 
                //before or after "foo()" has been called?
                //is it called?

}

并且,如果在调用foo之后才调用它,在调用foo()之前如何销毁v?

4 个答案:

答案 0 :(得分:2)

v = foo();

上述语句是移动分配(前C ++ 11编译器的复制分配)。在任何一种情况下,分配都需要调用foo()的结果,因为它是相应赋值运算符的输入参数,因此v管理的资源的释放已完成 调用foo()之后,内存管理在复制/移动赋值运算符中执行。

注意我没有提到对v析构函数的任何调用,因为在那一点上不会调用析构函数。将释放由v管理的内存,并调用各个元素的析构函数。如果是vector<int>,则每个int的析构函数都是NOP,因此它们仅在概念上被调用。

vector将分配足够的内存,以便能够保存vector返回的foo的内容(复制分配),或控制由...管理的内存vector返回foo(移动分配)。当然,如果现有内存足以容纳新内容,vector实现可以自由跳过释放,然后分配。

v的析构函数将在v超出范围时运行。在您提供的示例中,这发生在main()的末尾。

答案 1 :(得分:0)

foo()的返回值是在将v分配给main()中的{{1}}之前创建的。

答案 2 :(得分:0)

析构函数在超出范围时被调用,即在main的末尾。

顺序是你调用foo(),它返回一个向量。然后调用复制赋值运算符,它将返回的向量复制到原始向量。之后返回的向量将被销毁,因为它是一个临时变量。

答案 3 :(得分:0)

v只有在超出范围时才会被破坏。

但是,foo()会创建一个临时对象,然后返回该对象,然后将其分配给v。然后销毁临时(在将其分配给v之后)。然后在v结束时销毁main()

请注意,在实践中,编译器优化了很多 - 它执行了返回值优化,因此它不会返回临时值,而是将其分配给v,它可以正常工作直接在v。此外,还有一个移动赋值运算符,它将内存的所有权从临时转换为v而不先复制它。