大家帮忙算一算拷贝构造函数的调用次数
时间:2011-12-17
来源:互联网
#include<iostream> using namespace std; class Myclass { public: Myclass(int n) { number=n;} Myclass(const Myclass &oher) { number=other.number;} ~Myclass(); private: int number; }; Myclass fun(Myclass p) //1次 { Myclass temp(p);//1次 return temp;//1次,这里我认为系统会建立一个无名对象以存放temp的值,所以有一次赋值。 } int main() { Myclass obj1(10),obj2(0); Myclass obj3(obj1); //1次 obj2=fun(obj3); // fun(obj3)是3次,赋值又1次,所以这里是4次 return 0; } //综上共五次
想听听大家的看法!!!
作者: neolyao 发布时间: 2011-12-17
Google “NRVO”
作者: mougaidong 发布时间: 2011-12-17
作者: mougaidong 发布时间: 2011-12-17
作者: mougaidong 发布时间: 2011-12-17
赋值就是赋值,哪来的又一次,赋值调用的是赋值函数
赋值难道不调用构造函数吗??
作者: neolyao 发布时间: 2011-12-17
#include<iostream> using namespace std; class Myclass { public: Myclass(int n) { number=n;cout<<"Initialize !"<<endl; } Myclass(const Myclass &other) { number=other.number; cout<<"copy obj !"<<endl; } ~Myclass() { cout<<"release !"<<endl; } private: int number; }; Myclass fun(Myclass p) //1次 { Myclass temp(p);//1次 return temp;//1次,这里我认为系统会建立一个无名对象以存放temp的值,所以有一次赋值。 } int main() { Myclass obj1(10),obj2(0); Myclass obj3(obj1); //1次 obj2=fun(obj3); // fun(obj3)是3次,赋值又0次,所以这里是3次 return 0; } //综上共4次
作者: agoago_2009 发布时间: 2011-12-17
引用 3 楼 mougaidong 的回复:
赋值就是赋值,哪来的又一次,赋值调用的是赋值函数
赋值难道不调用构造函数吗??
要啊
作者: agoago_2009 发布时间: 2011-12-17
{
Myclass temp(p);//1次
return temp;///1次
}
int main()
{
Myclass obj1(10),obj2(0);
Myclass obj3(obj1); //1次
obj2=fun(obj3); // fun(obj3)是2次,赋值又1次,所以这里是3次
return 0;
}
作者: agoago_2009 发布时间: 2011-12-17
这里涉及到一个临时变量优化的问题,不同编译器下可能不一样
作者: qscool1987 发布时间: 2011-12-17
拷贝构造函数和赋值函数到底有什么差别呢?我想有人会说,没有差别。呵,如果没有差别,那么只要实现其中一个就行了,何必要两者都实现呢?不绕圈子了,它们的差别是:
拷贝构造函数对同一个对象来说只会调用一次,而且是在对象构造时调用。此时对象本身还没有构造(无空间),无需要去释放自己的一些资源。而赋值操作可能会调用多次,你在复制之前要释放自己的一些资源,否则会造成资源泄露。
对上面的内容作适当的说明:假设有类
C/C++ code
class A{ public: A(const int &a); //a A(const A&);//b A& operator=(const A&);//c …… Private: Int a; } //a行为一般构造函数,b行为拷贝构造函数,c行为赋值操作(即operator=重载) //(一) 默认成员函数 //当程序员没用自己定义的情况获一个空类,编译器会自动的为该类生成6个成员函数,分别为: //1个构造函数 //1个析构函数 //1个拷贝构造函数 //1个赋值操作函数operator= //2个取地址函数operator&,其中一个为const版本一个为非const版本
程序猿最好能够重新定义这些函数,以避免这些函数的自动调用产生不能预料的结果。这些自动生成的函数的实现部分:(参考effective C++条款45)
C/C++ code
inline A::A() {} inline A::~A() {} inline A * A::operator&() { return this; } inline const A * A::operator&() const { return this; }
(二) 拷贝构造函数
C/C++ code
A a1 = new A(); A a2(a1);//a A a3;//3 a3 = a1;//4
此处a2的构造使用的拷贝构造,这点基本上都能明白,也容易理解。等4行的a3调用赋值操作。
但有的时候 同样是=,确调用了拷贝构造,那到底
什么时候调用拷贝构造?
什么时候调用赋值操作?
A a1;
A a2 = a1; //b
上面中a2初始化,此处调用拷贝构造。
大家可能看出来了行a、b的差别。那行4与行b的差别呢:行4中调用赋值操作,是应为a3已经初始化过(行3),此时a3以调用A()进行了内存空间开辟。此时=只需要将a1中的内容复制到a3的存储空间中。所以使用的是复制操作(operator=);
行b的情况则是这样,由于a2刚定义,尚未有内存空间,并且需要用a1去初始化它,所以需要两部操作,1.为a2分配空间;2.a1内容复制到a2空间。这一行操作相当于行3+行4的效果。
另外拷贝构造还在如下地方隐含调用:
1. 函数参数传对象的值时
Bool Fun(A a);
A b;
Fun(b);//对象值传递
此时在开始Fun函数时会创建一个临时对象t_b,类似:
Bool Fun( A b){
A t_b(b); //a
……
}
A行后的内容针对t_b进行。
2. 函数返回临时对象时
A Fun(){
A temp;
Return temp;//b
}
此处b行也会隐含调用拷贝构造产生一个临时对象作为返回,而真正的temp在}后将背销毁。
这里说道隐含调用,提一下:
修饰符explicit:如果不希望构造被隐含转换,则可将其定义为explicit,则禁止“隐式“转换。某些情况下”隐式“将会产生错误。Explicit主要目的是指明一个函数的调用必须是显式的,副作用才是禁止隐式的类型转化。如:
函数 :
A& test(A&);
Test(2);//成功,做了隐式转换,将int 型2转换为A类型。
如果A类定义中的构造函数A(const int &a)加上explicit,则:
Test(2);//失败,参数类型不匹配错误。
同样的
A a=3;//失败 类似的情况
A a(3);//成功
作者: neolyao 发布时间: 2011-12-17
这里我找到一篇文章写的比较好:
拷贝构造函数和赋值函数到底有什么差别呢?我想有人会说,没有差别。呵,如果没有差别,那么只要实现其中一个就行了,何必要两者都实现呢?不绕圈子了,它们的差别是:
拷贝构造函数对同一个对象来说只会调用一次,而且是在对象构造时调用。此时对象本身还没有构造(无空间),无需要去释放自己的一些资源。而赋值操作可能会调用多次,你在复制之前要释放自己的一些资源,否则会造成资源泄……
学习了
作者: agoago_2009 发布时间: 2011-12-17
取决于赋值操作符怎么定义
用缺省的赋值操作符,你这里共拷贝赋值4次
C/C++ code
#define output(str) cout <<endl <<"\t" <<#str <<endl; str class Myclass { public: Myclass(int n):number(n){} Myclass(const Myclass &other):number(other.number){cout <<"copy constructor\t" <<number <<endl;} //Myclass& operator=(const Myclass &){cout <<"assignment operator\t" <<number <<endl;return *this;} Myclass operator=(const Myclass &){cout <<"assignment operator\t" <<number <<endl;return *this;} ~Myclass(){}; private: int number; }; Myclass fun(Myclass p) //1次 { output(Myclass temp(p);)//1次 output(return temp;)//1次 } int main() { output(Myclass obj1(10);) output(Myclass obj2(0);) output(Myclass obj3(obj1);) //1次 output(obj2=fun(obj3);) // fun(obj3)是3次,赋值又1次,所以这里是4次 output(return 0;) }
作者: yisikaipu 发布时间: 2011-12-17
C/C++ code
Myclass obj1(10); Myclass obj2(0); Myclass obj3(obj1); copy constructor 10 obj2=fun(obj3); copy constructor 10 Myclass temp(p); copy constructor 10 return temp; copy constructor 10 return 0; 请按任意键继续. . .
作者: yisikaipu 发布时间: 2011-12-17
C/C++ code
#define output(str) cout <<endl <<"\t" <<#str <<endl; str class Myclass { public: Myclass(int n):number(n){} Myclass(const Myclass &other):number(other.number){cout <<"copy constructor\t" <<number <<endl;} //Myclass& operator=(const Myclass &){cout <<"assignment operator\t" <<number <<endl;return *this;} //Myclass operator=(const Myclass &){cout <<"assignment operator\t" <<number <<endl;return *this;} ~Myclass(){}; private: int number; }; Myclass fun(Myclass p)//1次 { output(Myclass temp(p);)//1次 output(return temp;)//1次 } int main() { output(Myclass obj1(10);) output(Myclass obj2(0);) output(Myclass obj3(obj1);)//1次 output(obj2=fun(obj3);) output(return 0;) }
作者: yisikaipu 发布时间: 2011-12-17
Myclass fun(Myclass p)
{
Myclass temp(p);//1次
return temp;///1次
}
int main()
{
Myclass obj1(10),obj2(0);
Myclass obj3(obj1); //1次
obj2=fun(obj3); // fun(obj3)……
发错了的
作者: agoago_2009 发布时间: 2011-12-17
作者: neolyao 发布时间: 2011-12-17
1、debug版本,4次。
2、release版本,3次。
作者: mougaidong 发布时间: 2011-12-17
#include<iostream> using namespace std; class Myclass { public: Myclass(int n) { number=n;} Myclass(const Myclass &oher) { cout << "copy" << endl; } ~Myclass(){}; private: int number; }; Myclass fun(Myclass p) //1次 { Myclass temp(p);//1次 return temp;//1次,这里我认为系统会建立一个无名对象以存放temp的值,所以有一次赋值。 } int main() { Myclass obj1(10), obj2(0); Myclass obj3(obj1); //1次 obj2=fun(obj3); // fun(obj3)是3次,赋值又1次,所以这里是4次 return 0; }
作者: mougaidong 发布时间: 2011-12-17
已经亲测了,VS2008下:
1、debug版本,4次。
2、release版本,3次。
2、release版本,3次。
是不是“具名返回值优化可能会省掉一次”
作者: neolyao 发布时间: 2011-12-17
obj2=fun(obj3); // fun(obj3)是3次,赋值不会调用构造函数了,因为obj2已经存在,如何构造。 //所以这里是3次
作者: neolyao 发布时间: 2011-12-17
引用 16 楼 mougaidong 的回复:
已经亲测了,VS2008下:
1、debug版本,4次。
2、release版本,3次。
2、release版本,3次。
是不是“具名返回值优化可能会省掉一次”
是的
作者: mougaidong 发布时间: 2011-12-17
C/C++ code
obj2=fun(obj3); // fun(obj3)是3次,赋值不会调用构造函数了,因为obj2已经存在,如何构造。
//所以这里是3次
http://blog.csdn.net/mougaidong/article/details/6927216
作者: mougaidong 发布时间: 2011-12-17
这里我找到一篇文章写的比较好:
拷贝构造函数和赋值函数到底有什么差别呢?我想有人会说,没有差别。呵,如果没有差别,那么只要实现其中一个就行了,何必要两者都实现呢?不绕圈子了,它们的差别是:
拷贝构造函数对同一个对象来说只会调用一次,而且是在对象构造时调用。此时对象本身还没有构造(无空间),无需要去释放自己的一些资源。而赋值操作可能会调用多次,你在复制之前要释放自己的一些资源,否则会造成资源泄露……
这些说明的是拷贝构造和赋值的区别,并不能说明你这个问题,你这个问题我还是我上面说的编译器优化的问题,对于临时变量的拷贝构造不同的编译器优化效果还很有区别
Return temp;
这里肯定是先产生一个临时对象,这个临时对象如何产生就很讲究了
测试发现,vc下是创建一个临时对象将temp拷贝到临时对象中
GCC下目前还没看懂,优化的更厉害
作者: qscool1987 发布时间: 2011-12-17
作者: qscool1987 发布时间: 2011-12-17
热门阅读
-
office 2019专业增强版最新2021版激活秘钥/序列号/激活码推荐 附激活工具
阅读:74
-
如何安装mysql8.0
阅读:31
-
Word快速设置标题样式步骤详解
阅读:28
-
20+道必知必会的Vue面试题(附答案解析)
阅读:37
-
HTML如何制作表单
阅读:22
-
百词斩可以改天数吗?当然可以,4个步骤轻松修改天数!
阅读:31
-
ET文件格式和XLS格式文件之间如何转化?
阅读:24
-
react和vue的区别及优缺点是什么
阅读:121
-
支付宝人脸识别如何关闭?
阅读:21
-
腾讯微云怎么修改照片或视频备份路径?
阅读:28