国外财经网站是怎么做的,做网站注册公司,微信开发者工具简介,易班班级网站建设展示PPT最近在学习C的拷贝构造函数时发现一个问题#xff1a;在函数中返回局部的类对象时#xff0c;并没有调用拷贝构造函数。针对这个问题#xff0c;查阅了一些资料#xff0c;这里记录整理一下。
调用拷贝构造函数的三种情况#xff1a;
① 用一个类去初始化另一个对象时的拷贝构造函数时发现一个问题在函数中返回局部的类对象时并没有调用拷贝构造函数。针对这个问题查阅了一些资料这里记录整理一下。
调用拷贝构造函数的三种情况
① 用一个类去初始化另一个对象时初始化的为新对象
②一个对象作为参数以值传递的方式传入函数内
③ 返回值作为类对象函数执行完成返回调用时。
下面写了一个示例代码
#include iostream
#include string
using namespace std;
class Demo {
public:Demo(string name, int data) : m_name(name), m_data(data) {cout 默认构造函数 endl;}Demo(const Demo other) {cout 拷贝构造函数 endl;m_name other.m_name;m_data other.m_data;}Demo operator(const Demo other) {cout 拷贝赋值运算符重载 endl;m_name other.m_name;m_data other.m_data;return *this; //return *this 是为了可以连续赋值}Demo(const Demo other) {cout 移动构造函数 endl;m_name other.m_name;m_data other.m_data;}Demo operator(const Demo other) {cout 移动赋值运算符重载 endl;m_name other.m_name;m_data other.m_data;return *this;}
private:string m_name;int m_data;
};void test01()
{//默认构造Demo a(zhangsam, 10);Demo b(lisi, 20);//拷贝构造使用一个类去初始化另一个对象时Demo c a;//拷贝赋值运算符重载使用一个类对另一个对象赋值c b a;//移动构造。使用右值对象对初始化一个对象时Demo e move(a);//移动赋值运算符重载使用一个右值对象对另一个对象赋值e move(b);
}//当类对象做形参是调用拷贝构造函数
Demo test02(Demo d1)
{Demo f(wangwu, 30);//返回一个类对象时这里调用了移动构造函数//这里编译器默认优化需要增加-fno-elide-constructor编译选项但是调用的确实移动构造函数//原因是在新的标砖中当编译器识别到返回的是一个局部的对象将自动使用move转化。//前提是类中自定义了移动构造函数否则将调用拷贝构造函数return f;
}
int main()
{test01();cout ----------- endl;Demo a1(test, 40);test02(a1);cout ----------- endl;return 0;
}最开始正常编译 g test.cpp
执行结果 可以看到test02函数最后返回一个f对象但是并没有调用拷贝构造函数。
① Demo a1(test, 40); //默认构造函数
② a1形参传参 //拷贝构造函数
③ 函数内 Demo f(wangwu, 30); //默认构造函数
④ return f //未打印任何东西 查阅资料后说是需要增加一个编译选项 -fno-elide-constructors 果然增加后出现了相应的打印。 但是为什么是调用的移动构造函数。。。 再次查阅资料到当从同类型的右值亡值将亡值或纯右值C17前亡值初始化直接初始化或者复制初始化对象时会调用移动构造函数情况包括
1、初始化 T a std::move(b) 或 T astd::move(b)
2、函数实参传递 f(std::move(a)) 其中a的类型是T 且f 是Ret f (T t);
3、函数返回在像T f() 这样的函数中的retuen a其中a的类型是T 且T中自定义了移动构造函数。 所以函数中的局部类对象其实是一个将亡值 然后又百度了下将亡值的概念和定义 就传统的理解而言函数foo的返回值在内部创建然后被赋值给v外部接收返回值的对象然后v获得这个对象时会将整个temp拷贝一份然后把temp销毁。如果这个temp非常大这将造成大量额外的开销这也是c一直被诟病的问题。在新的特性里面会自动检测这个值是不死局部的是的话就直接move()了。用不同的编译器不同的开关debugrelese结果可能都不一样。 例如一个函数v foo(接收返回值的v是一个左值foo()返回的值也就是一个右值也是纯右值。但是v可以被别的变量捕获到而foo()产生的那个返回值作为一个临时变量一旦被v赋值后将立即被销毁无法获取也不能修改。