何时调用复制构造函数和析构函数,为什么调用
When are copy constructors and destructors called, and why?
代码为:
#include <iostream>
class P_Node {
friend class Picture;
protected:
P_Node() : use(1) {}
virtual ~P_Node() {}
private:
int use;
};
class Picture {
friend Picture frame(const Picture&);
public:
Picture() : p(new P_Node) {
std::cout << "Constructort" << "Picture::Picture()" << "tcalled" << std::endl;
std::cout << "Picture p countt" << p->use << std::endl;
}
Picture(const Picture& orig) : p(orig.p) {
std::cout << "Copy Constructort" << "Picture::Picture(const Picture&)" << "tcalled" << std::endl;
std::cout << "Picture p countt" << p->use << std::endl;
orig.p->use++;
}
~Picture() {
std::cout << "Destructort" << "Picture::~Picture()" << "tcalled" << std::endl;
std::cout << "Picture p count before decreaset" << p->use << std::endl;
if(--p->use == 0) {
std::cout << "Picture p count after decreaset" << p->use << std::endl;
std::cout << "Deleted" << std::endl;
delete p;
}
}
Picture& operator=(const Picture& orig) {
std::cout << "operator=t" << "Picture& Picture::operator=(const Picture& orig)" << "tcalled" << std::endl;
std::cout << "Picture p count before decreaset" << p->use << std::endl;
orig.p->use++;
if(--p->use == 0) {
std::cout << "Picture p count after decreaset" << p->use << std::endl;
std::cout << "Deleted" << std::endl;
delete p;
}
p = orig.p;
return *this;
}
private:
Picture(P_Node* p_node) : p(p_node) {
std::cout << "Picture::Picture(P_Node* p_node)tcalled" << std::endl;
}
P_Node *p;
};
class Frame_Pic : public P_Node {
friend Picture frame(const Picture&);
private:
Frame_Pic(const Picture& pic) : p(pic) {
std::cout << "Frame_Pic::Frame_Pic(const Picture& orig)" << "tcalled" << std::endl;
}
Picture p;
};
Picture frame(const Picture& pic) {
return new Frame_Pic(pic);
}
int main() {
Picture my_pic;
Picture temp = frame(my_pic);
return 0;
}
结果是:
<>之前构造函数Picture::Picture()被调用图片p计数1复制构造函数Picture::Picture(const Picture&)被调用图片p计数1Frame_Pic(const Picture& origin)被调用图片:图片(P_Node* P_Node)被调用析构函数Picture::~Picture()被调用图片计数前减少1图像p计数下降0后删除析构函数Picture::~Picture()被调用图片计数前减少2析构函数Picture::~Picture()被调用图片计数前减少1图像p计数下降0后删除
我之前问了一个关于这段代码的内存管理的问题,但是在理解了答案之后,我仍然对析构函数和复制构造函数有一个问题。在我的理解中,Picture temp = frame(my_pic)
将调用复制构造函数。
- 为什么不在
Picture temp = frame(my_pic)
之后调用复制构造函数? - 为什么要调用析构函数?
- 在
Picture frame(const Picture& pic)
中,如果函数被调用,复制构造函数会被调用吗?我相信是这样,因为它返回一个'图片'的值。 - 如果我把
Picture frame(const Picture& pic)
改为Picture frame(Picture p)
,当函数被调用时,复制构造函数会调用两次吗? - 何时调用复制构造函数?当类由函数按值返回时,会发生这种情况吗?当然后类传递给一个函数的值? 什么时候调用析构函数?是每次变量生命周期结束的时候吗?这是否意味着如果我通过值传递一个变量给一个函数,它的析构函数将在函数执行后被调用?
我现在搞混了复制构造函数和析构函数,特别是当我有一个带有返回值的函数,并且一些参数都是通过值传递的。
还有,谁能帮我在每一行的输出字符串上写一个注释?那太有帮助了。
回答你的问题。
-
复制构造函数没有在语句
Picture temp = frame(my_pic);
之后调用,因为您没有任何语句导致该语句之后的任何复制。 -
Picture
的三个析构函数被调用,在temp.p
和my_pic
所指向的Frame_Pic
中依次销毁:temp
、p
。您的编译器已避免生成任何其他临时Picture
对象 -
是的,可以调用复制构造函数来初始化
Picture frame(const Picture& pic)
的返回值,但是编译器被允许(在这种情况下)消除复制并直接从返回表达式初始化返回值。 -
是的,如果你将
frame
的形参改为按值传递,可能会生成一个额外的复制构造函数调用,但如果形参初始化时使用的表达式不是指向现有对象的glvalue,则实参可能直接使用该表达式初始化,并省略副本。 -
每当实际复制类类型的对象时,就调用复制构造函数。这可能是在传递给函数或从函数返回时,但有时编译器允许在这些情况下省略不必要的副本。
-
是的,只要类类型的对象被销毁,就调用析构函数。对于编译器生成的命名变量和临时变量,这是正确的。可以在不调用析构函数的情况下结束对象的生命周期,例如为另一个对象重用它的内存,但这是非常特殊的情况。
复制构造函数不一定在您认为可能或应该调用的时候调用:
从维基百科。下列情况可能导致调用复制构造函数:
这些情况统称为复制初始化,相当于:
- 当对象返回值
时- 当一个对象作为参数值传递(给函数)
- 抛出对象时
- 对象被捕获时
- 当对象被放置在用大括号括起来的初始化列表中时
T x = a
;然而,不能保证在这些情况下会调用复制构造函数,因为c++标准允许编译器将拷贝优化掉在某些情况下,返回值优化就是一个例子(有时称为RVO)。
堆栈上的任何对象的析构函数在超出作用域时被调用。
注意:在所有声明将调用复制构造函数的答案中,有可能因为编译器做了一些优化而不会被调用。
1)为什么复制构造函数不在
Picture temp = frame(my_pic)
之后调用?
图片temp = frame(my_pic);在return语句之前的最后一行,因此在它之后发生的所有事情都被取消(调用析构函数,清除堆栈和堆)并结束。
2)为什么调用析构函数?
析构函数(在这里的每种情况下)由于程序关闭而被调用。注意:虽然这确实发生在程序结束时,但这并不意味着您不应该在自己之后进行清理!
3)在
Picture frame(const Picture& pic)
中,如果调用函数,会调用复制构造函数吗?
。你没有复制,你传递了一个引用到它所在的位置,并创建了一个新的,编译器将在返回时优化出副本。
4)如果我将
Picture frame(const Picture& pic)
更改为Picture frame(Picture p)
,在调用函数时是否会调用两次复制构造函数?
。它可能在你进入函数时被调用,但编译器会在返回时优化出副本。
5)何时调用复制构造函数?当类由函数按值返回时,会发生这种情况吗?当然后类传递给一个函数的值?
两种情况下都将调用复制构造函数
6)何时调用析构函数?变量的生命周期何时结束?这是否意味着如果我通过值将变量传递给函数,它的析构函数将在函数执行后被调用?
当对象被销毁时,析构函数将被调用。这可能是因为您销毁了它,或者包含它的函数返回(结束),并且它的变量/对象从堆栈中删除,或者在某些情况下(在程序结束时)从堆中删除。
- 为什么使用 "this" 指针调用派生成员函数?
- 为什么我的C#代码在调用回C++COM直到Task时会暂停.等待/线程.加入
- 为什么 std::unique 不调用 std::sort?
- C++为什么尽管我调用了void函数,它却不起作用
- 为什么使用 P/Invoke 调用 dll 时,某些计算机中的 LoadLibrary 失败?
- 为什么我不能在 C++ 中的特定函数重载中调用同一函数的任何其他重载?
- 为什么我的 IExtractIcon 处理程序没有被调用?
- 为什么类中的ostringstream类型的成员会导致";调用隐含删除复制构造函数";错误
- 为什么在使用转换构造函数赋值后调用C++类的析构函数?
- 为什么调用堆栈数组会导致内存泄漏
- 循环中的条件:为什么每次都调用strlen(),而vector.size()只调用一次
- 通过引用传递-为什么要调用这个析构函数
- WIN32:C++,为什么在WM_CLOSE上调用Messagebox函数程序正在冻结
- 为什么在 x64 中忽略__stdcall调用约定?
- 为什么不调用移动构造函数?(默认情况下只有构造器,没有别的)
- 为什么 zlib 放气初始化调用一次不起作用?
- 为什么默认复制函数在按值发送参数时不调用?
- 如果整个应用程序是虚拟映射的,为什么 new 会进行系统调用?
- Java用JNI调用C++:为什么JNIEnv指针被取消引用两次
- 在移动构造函数的缺席中,复制构造函数被调用?为什么呢?