如果我为旧变量分配一个新变量,旧变量不再可寻址,但是我不确定它何时超出范围:
例如:
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?
答案 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
而不先复制它。