当我按值传递参数时对象被破坏了?
When the object destructed while I pass the argument by-value?
给定以下代码:
#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;
}
我得到以下输出:
applying function f:
A copy ctor
This is A
A copy ctor
This is A
A dtor
A dtor
~~~ delete: ~~~
B dtor
A dtor
但是我有些不明白。可以看出,虽然我们从 f
存在,但那里的对象没有被破坏。为什么它没有被破坏? (毕竟,我们超出了函数的范围,所以它必须被销毁,不是吗?)
注意:我强调了有问题的行(我不明白为什么会按这个顺序出现)
我们转到函数 f,此时,我们调用复制 c'tor 并打印 "A copy ctor" (Ok) ,之后,我们 returns 转到函数 f 并转到到 type() ,然后打印 "This is A" ,现在我们从函数 f 中退出,所以我们调用复制 c'tor ,因此将被打印 "A copy ctor" ,但是,现在,析构函数是什么没有被调用(当我们从函数 f 中逃脱时)..?
我认为输出将是以下内容(根据上面的描述):
applying function f:
A copy ctor
This is A
A copy ctor (escape from type
)
A dtor (escape from type
)
This is A (at the main)
~~~ delete: ~~~
B dtor
A dtor
C++ 标准允许按值函数参数在函数范围内或调用范围内销毁。
如果在调用范围内,它在完整表达式的末尾被销毁(通常是 ;
)。如果在函数内部,构造return值后销毁,销毁自动存储局部变量。
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
的副本,但它只是 *pa
.
的 A
部分的副本
输出是 This is A
,后跟 A(A&&)
移动构造函数,后跟可选的 A dtor
。在你的情况下,你有一个复制 ctor 而不是移动 ctor,所以它被称为。这个 copy/move 不能省略,因为不允许从函数参数中省略。输出为 A copy ctor
.
此时,编译器可以选择性地销毁作为 f
参数的 A
。您的编译器不会在此处破坏 f
的参数。
f(*pa).type();
由 f
编辑的临时 A
return 现在调用了 .type()
。这里没有多态性;方法 A::type()
被直接调用。输出为 This is A
.
然后我们到达了完整表达式的结尾。
现在由 f
编辑的临时 return 被销毁,如果它之前没有被销毁,后面是 f
的参数。所以输出是 A dtor
.
cout << "~~~ delete: ~~~" << endl;
delete pa;
B
对象*pa
被销毁,然后回收内存。由于 ~A
是虚拟的,因此在 *pa
.
上调用了正确的析构函数
输出为 B dtor\nA dtor\n
。
当函数参数被破坏时的行为是实现定义的:
It is implementation-defined whether the lifetime of a parameter ends when the function in which it is defined returns or at the end of the enclosing full-expression.
在您的特定情况下,实施选择后者。
给定以下代码:
#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;
}
我得到以下输出:
applying function f:
A copy ctor
This is A
A copy ctor
This is A
A dtor
A dtor
~~~ delete: ~~~
B dtor
A dtor
但是我有些不明白。可以看出,虽然我们从 f
存在,但那里的对象没有被破坏。为什么它没有被破坏? (毕竟,我们超出了函数的范围,所以它必须被销毁,不是吗?)
注意:我强调了有问题的行(我不明白为什么会按这个顺序出现)
我们转到函数 f,此时,我们调用复制 c'tor 并打印 "A copy ctor" (Ok) ,之后,我们 returns 转到函数 f 并转到到 type() ,然后打印 "This is A" ,现在我们从函数 f 中退出,所以我们调用复制 c'tor ,因此将被打印 "A copy ctor" ,但是,现在,析构函数是什么没有被调用(当我们从函数 f 中逃脱时)..?
我认为输出将是以下内容(根据上面的描述):
applying function f:
A copy ctor
This is A
A copy ctor (escape fromtype
)
A dtor (escape fromtype
)
This is A (at the main)
~~~ delete: ~~~
B dtor
A dtor
C++ 标准允许按值函数参数在函数范围内或调用范围内销毁。
如果在调用范围内,它在完整表达式的末尾被销毁(通常是 ;
)。如果在函数内部,构造return值后销毁,销毁自动存储局部变量。
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
的副本,但它只是 *pa
.
A
部分的副本
输出是 This is A
,后跟 A(A&&)
移动构造函数,后跟可选的 A dtor
。在你的情况下,你有一个复制 ctor 而不是移动 ctor,所以它被称为。这个 copy/move 不能省略,因为不允许从函数参数中省略。输出为 A copy ctor
.
此时,编译器可以选择性地销毁作为 f
参数的 A
。您的编译器不会在此处破坏 f
的参数。
f(*pa).type();
由 f
编辑的临时 A
return 现在调用了 .type()
。这里没有多态性;方法 A::type()
被直接调用。输出为 This is A
.
然后我们到达了完整表达式的结尾。
现在由 f
编辑的临时 return 被销毁,如果它之前没有被销毁,后面是 f
的参数。所以输出是 A dtor
.
cout << "~~~ delete: ~~~" << endl;
delete pa;
B
对象*pa
被销毁,然后回收内存。由于 ~A
是虚拟的,因此在 *pa
.
输出为 B dtor\nA dtor\n
。
当函数参数被破坏时的行为是实现定义的:
It is implementation-defined whether the lifetime of a parameter ends when the function in which it is defined returns or at the end of the enclosing full-expression.
在您的特定情况下,实施选择后者。