当前位置: 首页 > news >正文

哪里可以买域名做网站制作网页的三大技术是哪些

哪里可以买域名做网站,制作网页的三大技术是哪些,自已做好的网站怎么做后台,长沙网站建设王道下拉棒C11移动构造函数详解 拷贝构造函数修改后的拷贝构造函数移动构造函数移动构造函数的优点 当类中同时包含拷贝构造函数和移动构造函数时,如果使用临时对象初始化当前类的对象,编译器会优先调用移动构造函数来完成此操作。只有当类中没有合适的移动构造函数…

C++11移动构造函数详解

  • 拷贝构造函数
  • 修改后的拷贝构造函数
  • 移动构造函数
  • 移动构造函数的优点

当类中同时包含拷贝构造函数和移动构造函数时,如果使用临时对象初始化当前类的对象,编译器会优先调用移动构造函数来完成此操作。只有当类中没有合适的移动构造函数时,编译器才会退而求其次,调用拷贝构造函数。

拷贝构造函数

C++在三种情况下会调用拷贝构造函数(可能有纰漏),第一种情况是函数形实结合时,第二种情况是函数返回时,函数栈区的对象会复制一份到函数的返回去,第三种情况是用一个对象初始化另一个对象时也会调用拷贝构造函数

除了这三种情况下会调用拷贝构造函数,另外如果将一个对象赋值给另一个对象,这个时候回调用重载的赋值运算符函数。

无论是拷贝构造函数,还是重载的赋值运算符函数,我记得当时在上C++课的时候,老师再三强调,一定要注意指针的浅层复制问题。

这里在简单回忆一下拷贝构造函数中的浅层复制问题

首先看一个浅层复制的代码:

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <vector>using namespace std;class Str{public:char *value;Str(char s[]){cout<<"调用构造函数..."<<endl;int len = strlen(s);value = new char[len + 1];memset(value,0,len + 1);strcpy(value,s);}Str(Str &v){cout<<"调用拷贝构造函数..."<<endl;this->value = v.value;}~Str(){cout<<"调用析构函数..."<<endl;if(value != NULL)delete[] value;}
};int main()
{char s[] = "I love BIT";Str *a = new Str(s);Str *b = new Str(*a);delete a;cout<<"b对象中的字符串为:"<<b->value<<endl;delete b;return 0;
}

输出结果为:

调用构造函数...
调用拷贝构造函数...
调用析构函数...
b对象中的字符串为:
调用析构函数...

首先结果并不符合预期,我们希望b对象中的字符串也是I love BIT但是输出为空,这是因为b->value和a->value指向了同一片内存区域,当delete a的时候,该内存区域已经被收回,所以再用b->value访问那块内存实际上是不合适的,而且,虽然我运行时程序没有崩溃,但是程序存在崩溃的风险呀,因为当delete b的时候,那块内存区域又被释放了一次,两次释放同一块内存,相当危险呀。

因此对于类中的指针数据成员,必须采用深层复制的方式进行拷贝,深层复制的代码如下:

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <vector>using namespace std;class Str{public:char *value;Str(char s[]){cout<<"调用构造函数..."<<endl;int len = strlen(s);value = new char[len + 1];memset(value,0,len + 1);strcpy(value,s);}Str(Str &v){cout<<"调用拷贝构造函数..."<<endl;int len = strlen(v.value);value = new char[len + 1];memset(value,0,len + 1);strcpy(value,v.value);}~Str(){cout<<"调用析构函数..."<<endl;if(value != NULL){delete[] value;value = NULL;}}
};int main()
{char s[] = "I love BIT";Str *a = new Str(s);Str *b = new Str(*a);delete a;cout<<"b对象中的字符串为:"<<b->value<<endl;delete b;return 0;
}

运行结果为:

调用构造函数.. .
调用拷贝构造函数...
调用析构函数...
b对象中的字符串为:l love BIT
调用析构函数...

修改后的拷贝构造函数

有时候我们会遇到这样一种情况,我们用对象a初始化对象b,后对象a我们就不在使用了,但是对象a的空间还在呀(在析构之前),既然拷贝构造函数,实际上就是把a对象的内容复制一份到b中,那么我们可以对指针进行浅复制,这样就避免了新的空间的分配,大大降低了构造的成本。

但是上面提到,指针的浅层复制是非常危险的呀。没错,确实很危险,而且通过上面的例子,我们也可以看出,浅层复制之所以危险,是因为两个指针共同指向一片内存空间,若第一个指针将其释放,另一个指针的指向就不合法了。所以我们只要避免第一个指针释放空间就可以了。避免的方法就是将第一个指针(比如a->value)置为NULL,这样在调用析构函数的时候,由于有判断是否为NULL的语句,所以析构a的时候并不会回收a->value指向的空间(同时也是b->value指向的空间)

所以我们可以把上面的拷贝构造函数的代码修改一下:

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <vector>using namespace std;class Str{public:char *value;Str(char s[]){cout<<"调用构造函数..."<<endl;int len = strlen(s);value = new char[len + 1];memset(value,0,len + 1);strcpy(value,s);}Str(Str &v){cout<<"调用拷贝构造函数..."<<endl;this->value = v.value;v.value = NULL;}~Str(){cout<<"调用析构函数..."<<endl;if(value != NULL)delete[] value;}
};int main()
{char s[] = "I love BIT";Str *a = new Str(s);Str *b = new Str(*a);delete a;cout<<"b对象中的字符串为:"<<b->value<<endl;delete b;return 0;
}

运行结果为:

调用构造函数...
调用拷贝构造函数...
调用析构函数...
b对象中的字符串为:l love BIT
调用析构函数...

修改后的拷贝构造函数,采用了浅层复制,但是结果仍能够达到我们想要的效果,关键在于在拷贝构造函数中,最后我们将v.value置为了NULL,这样在析构a的时候,就不会回收a->value指向的内存空间。

这样用a初始化b的过程中,实际上我们就减少了开辟内存,构造成本就降低了。

但要注意,我们这样使用拷贝构造函数有一个前提是:用a初始化b后,a我们就不需要了,最好是初始化完成后就将a析构。如果说,我们用a初始化了b后,仍要对a进行操作,用这种浅层复制的方法就不合适了

所以C++引入了移动构造函数,专门处理这种用a初始化b后就将a析构的情况。

移动构造函数

移动构造函数的参数和拷贝构造函数不同,拷贝构造函数的参数是一个左值引用,但是移动构造函数的初值是一个右值引用。这意味着,移动构造函数的参数是一个右值或者将亡值的引用。也就是说,只用用一个右值,或者将亡值初始化另一个对象的时候,才会调用移动构造函数。移动构造函数的例子如下:

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <vector>
using namespace std;class Str{public:char *str;Str(char value[]){cout<<"普通构造函数..."<<endl;str = NULL;int len = strlen(value);str = (char *)malloc(len + 1);memset(str,0,len + 1);strcpy(str,value);}Str(const Str &s){cout<<"拷贝构造函数..."<<endl;str = NULL;int len = strlen(s.str);str = (char *)malloc(len + 1);memset(str,0,len + 1);strcpy(str,s.str);}Str(Str &&s){cout<<"移动构造函数..."<<endl;str = NULL;str = s.str;s.str = NULL;}~Str(){cout<<"析构函数"<<endl;if(str != NULL){free(str);str = NULL;}}
};
int main()
{char value[] = "I love zx";Str s(value);vector<Str> vs;//vs.push_back(move(s));vs.push_back(s);cout<<vs[0].str<<endl;if(s.str != NULL)cout<<s.str<<endl;return 0;
}

在此构造函数中,num 指针变量采用的是浅拷贝的复制方式,同时在函数内部重置了 d.num,有效避免了“同一块对空间被释放多次”情况的发生

当类中同时包含拷贝构造函数和移动构造函数时,如果使用临时对象初始化当前类的对象,编译器会优先调用移动构造函数来完成此操作。只有当类中没有合适的移动构造函数时,编译器才会退而求其次,调用拷贝构造函数。

使用move()函数,可以将一个左值变成右值,因此a=move(b)调用的是移动构造函数

移动构造函数的优点

移动构造函数是c++11的新特性,移动构造函数传入的参数是一个右值 用&&标出。

首先讲讲拷贝构造函数:拷贝构造函数是先将传入的参数对象进行一次深拷贝,再传给新对象。这就会有一次拷贝对象的开销,并且进行了深拷贝,就需要给对象分配地址空间。而移动构造函数就是为了解决这个拷贝开销而产生的。移动构造函数首先将传递参数的内存地址空间接管,然后将内部所有指针设置为nullptr,并且在原地址上进行新对象的构造,最后调用原对象的的析构函数,这样做既不会产生额外的拷贝开销,也不会给新对象分配内存空间

http://www.yayakq.cn/news/262243/

相关文章:

  • 网站链接锚文字怎么做如何做电商创业
  • 陕西省建设厅管理中心网站创意平面设计公司公司排名
  • 之前做的网站推广怎么删除中国建设银行手机登录
  • 网站建设需要报告网站建设就是学淘宝吗
  • 网站开发者模式专门查公司的软件
  • 宁德网站开发公司外包做网站要十几万
  • 网站如何跟域名绑定石家庄网站免费制作
  • 东莞南城做网站推广的公司wordpress 主题新建页面
  • 长乐区住房和城乡建设局网站伊犁园xyz视频人入口
  • 怎样把自己的网站上传学平面设计要多少钱
  • 南京原创网站建设怎么联系网络公司推广软文
  • 网站建设 代理网站架构原理
  • 温州做模具的网站做网站宜宾
  • 沈阳个人网站建设一个网站可以做多少弹窗广告
  • 做界面网站用什么语言深圳软装设计公司有哪些
  • 怎样注册免费网站wordpress 打不开页面
  • 马蜂窝网站怎么做创建网站需要什么平台
  • 唐山建站公司中国室内设计师网官网
  • 广州知名网站网站开发在哪个科目核算
  • 手机网站推广怎么做google 网站收录
  • 云南俊发建设集团网站商城网站的模块设计
  • 短租房网站哪家做最好郑州好的网站建站
  • 模块化建站工具建筑做网站
  • 网站维护一般做什么互联网基础知识入门
  • 广州番禺网站推广wordpress 对空间要求
  • 营销型网站模板免费下载广告推广方案
  • 计算机网站开发岗位有哪些成为网站开发工程师
  • 做网站公司 蓝纤科技东莞网站制作电话
  • 程序员做外包网站wordpress 苏醒主题
  • 手机型网站免费二维码生成工具