y-finput-charset=UTF-8
-fexec-charset=UTF-8
移动构造函数
复制构造函数通过复制的方式构造新的对象,但很多时候被复制的对象仅作复制之后销毁,影响程序的性能。
复制–>移动
左值(lvalue)和右值(rvalue)
·能具名,能取地址
·不具名,不能取地址
·int i=0; //i是左值,0是右值
·int &j=i; //左值引用
e.g. int i=fun();
- 左值i //在表达式结束之后仍然存在
- fun()函数返回的临时整型值,在表达式结束后销毁
- 这个临时值就是右值
e.g. int &&k=fun();
- 右值引用
- 右值是匿名变量,只能通过引用的方式来获取右值
- fun()产生的临时值在表达式结束后不会销毁,生命周期会延长,与k一样
- 右值引用绑定了右值,让右值的生命周期延长
关闭编译器返回值优化:
-fno-elide-constructors
e.g. const A &a=fun();
- C++98/03做性能优化
常量左值引用:万能引用类型
- 可以接受的值:左值、常量左值
右值、常量右值
非常量左值引用:只能接受左值
- A& a=fun(); //错误
https://blog.csdn.net/qq_30460949/article/details/89075879
https://blog.csdn.net/wdl20170204/article/details/111615408
C++11的move语义
std::move是获得右值的方式,标准库utility中声明了move函数将将左值对象移动成为右值
-
std::move
-
将资源的所有权从一个对象转移到另一个对象
-
只是转移,没有内存的拷贝
-
A(string s)😒(std::move(s){ //笑脸是: s,中间没空格
}
-
A(A &&a)noexcept:s(std::move(a.s){
}
e.g.
float n=10;
float &&rr_n=std::move(n); //将左值对象移动为右值并绑定右值引用
//move函数告诉编译器变量n转换为当右值来使用,承诺除对n重新赋值或者销毁它以外,将不再通过rr_n右值引用的方式使用它。
如果一个对象内部有较大的内存或动态数组时,有必要写移动构造函数和移动赋值函数,避免无谓的复制,提高性能。
移动构造函数
基于右值引用的新设定,可以通过移动而不复制实参的高性能方式构建新对象,即移动构造函数。类似于复制构造函数,移动构造函数的参数为该类对象的右值引用,在构造中移动源对象资源,构造后源对象不再指向被移动的资源,源对象可重新赋值或者被销毁。
A(A &&a){
}
e.g.
class MyStr{
public:
string s;
MyStr ( ) : s (" “) { }; //无参构造函数
MyStr (string_s) : s (std::move(_s)) { }; //有参构造函数
MyStr (MyStr &&str) noexcept //告知编译器不抛出异常
: s (std::move(str.s) { } //移动构造函数
注意:在提供移动构造函数的同时,也提供复制构造函数,以防止移动不成功的时候还能进行复制构造,使代码更安全。
default函数 delete函数
C++11标准提供以简化构造函数的定义与使用
=default显式要求编译器自动生成默认或复制构造函数
class MyStr {
public:
string s;
MyStr() =default;//默认合成的无参构造函数
MyStr(string_s) : s(std::move(_s)) {};//有参构造函数
MyStr(MyStr &&str)=default;//默认合成的复制构造函数
~MyStr()=default;//默认合成的析构函数
};
通过使用default,可以使编译器合成简单的无参默认构造函数和复制构造函数,但其他使用残都构造函数,由于编译器不知构造逻辑,需要用户自行定义
=delete显示要求编译器删除构造函数(析构函数除外)
- A( )=delete;
- A(const A&a)=delete;
类设计者的核查清单
- 你的数据成员是私有的吗?
- 你的类需要一个构造函数吗?
- 你的类需要一个无参构造函数吗?
- 是不是每个构造函数初始化所有的数据成员?
- 你的类需要析构函数吗?该类是否分配了资源,而该资源又不会由成员函数自动释放?57543546
- 你的类需要复制构造函数吗?
- 记得在辅助构造函数和赋值运算函数中的参数类型中加上const了吗?
- 如果函数有引用参数,它们应该是const引用吗?
类的大小
class A{
};
cout<<sizeof(A);
- 输出结果:1
- 在大多数编译器中,空类是可以实例化的
- 类的每个实例在内存中都有一个独一无二的地址
- 为了达到这个目的,编译器会给一个空类隐含地加一个字节
- 类的大小(一般情况下):
·类的非静态数据成员的类型大小之和
·为了优化存取效率,进行边缘调整
·与类中的构造函数、析构函数及成员函数无关(虚函数
除外)
空类有成员函数吗?
class Empty{
public:
Empty();
Empty(const Empty & );
Empty &operator=(const Empty & );
~Empty();
};
for(inn i=0;i<1000000;++i){
Emoty em;
em.show(i);
} //构造函数和析构函数分别调用1000000次!
修改为:
Empty em;//构造函数和析构函数只调用1次
for(int i=0;i<1000000;++i){
em.shou(i);
}