0
点赞
收藏
分享

微信扫一扫

4.3.6-.4.3.7移动构造函数 default delete 左值右值 move

zmhc 2022-03-13 阅读 22

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);
 }
举报

相关推荐

左值和右值

0 条评论