给出以下代码:
#include <iostream>
using namespace std;
class A {
public:
A() {
}
A(const A& a) {
cout << "A copy ctor" << endl;
}
virtual ~A() {
cout << "A dtor" << endl;
}
virtual void type() const {
cout << "This is A" << endl;
}
};
class B: public A {
public:
virtual ~B() {
cout << "B dtor" << endl;
}
virtual void type() const {
cout << "This is B" << endl;
}
};
A f(A a) {
a.type();
return a;
}
const A& g(const A& a) {
a.type();
return a;
}
int main() {
A *pa = new B();
cout << "applying function f:" << endl;
f(*pa).type();
cout << "~~~ delete: ~~~" << endl;
delete pa;
return 0;
}
我得到以下输出:
应用功能f:
复制ctor
这是A
复制ctor
这是A
dtor
dtor
~~~删除:~~~
兄弟
dtor
但是我听不懂。可以看出,尽管我们从f
存在,但对象没有被破坏。为什么它不被破坏? (毕竟,我们超出了函数的范围,因此必须销毁它,不是吗?)
注意:我强调了有问题的台词(我不明白为什么会按此顺序发生)
我们转到函数f,这时,我们调用副本c'tor并打印“ A copy ctor”(Ok),之后,我们返回函数f并转到type(),然后然后,它打印“ This is A”,现在我们从函数f中退出,所以我们调用了副本c'tor,因此将打印“ A copy ctor”,但是,现在,析构函数没有被调用(当我们逃脱功能f)..?
我认为输出将是以下内容(根据上面的描述):
应用功能f:
复印机
这是A
复制副本(从type
退出)
干事(从type
逃出)
这是A (主要)
~~~删除:~~~
Bdtor
干事
答案 0 :(得分:3)
C ++标准允许在函数范围内或调用范围内销毁按值函数参数。
如果在调用范围内,则在完整表达式(通常为;
)的末尾销毁它。如果在函数内,则在构造返回值并销毁自动存储本地变量后销毁它。
A *pa = new B();
创建了一个B
,带有一个A
子对象。
cout << "applying function f:" << endl;
f(*pa)//.type();
创建*pa
的切片副本作为f
的参数。输出为A copy ctor\n
。
A f(A a) {
a.type();
return a;
}
一个.type
。在A
的实例上调用。请注意,此A
是*pa
的副本,但仅是A
的{{1}}部分的副本。
输出为*pa
,然后是This is A
移动ctor,然后是A(A&&)
。在您的情况下,您有一个复制ctor,而不是一个移动ctor,因此被称为。无法删除此复制/移动,因为不允许您从函数参数中删除。输出为A dtor
。
这时,编译器可以选择将A copy ctor
的自变量A
进行销毁。您的编译器不会破坏f
的参数。
f
由f(*pa).type();
返回的临时A
现在已被调用f
。这里没有多态性。方法.type()
被直接调用。输出为A::type()
。
然后我们到达完整表达式的结尾。
现在,由This is A
返回的临时文件将被销毁,如果没有更早地销毁,则由f
的参数跟随。因此输出为f
。
A dtor
cout << "~~~ delete: ~~~" << endl;
delete pa;
对象B
被销毁,然后内存被回收。由于*pa
是虚拟的,因此会在~A
上调用适当的析构函数。
输出为*pa
。
答案 1 :(得分:2)