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

农村网站建设调查报告兰州市城乡建设局网站官网

农村网站建设调查报告,兰州市城乡建设局网站官网,网站打开慢的原因,易班网站建设b站Cherno的课[86]-[90] 一、C持续集成二、C静态分析三、C的参数计算顺序四、C移动语义五、stdmove与移动赋值操作符 一、C持续集成 Jenkins 商业软件 二、C静态分析 静态分析器会检查你的代码,并尝试检测各种错误,这些错误 可能是你无意中编写的&am…

b站Cherno的课[86]-[90]

  • 一、C++持续集成
  • 二、C++静态分析
  • 三、C++的参数计算顺序
  • 四、C++移动语义
  • 五、stdmove与移动赋值操作符

一、C++持续集成

Jenkins 商业软件
在这里插入图片描述

二、C++静态分析

静态分析器会检查你的代码,并尝试检测各种错误,这些错误
可能是你无意中编写的,有点像代码复查,但不是由人来做

PVS-Studio 商业软件

三、C++的参数计算顺序

(参数求值顺序)
argument evaluation order

未定义的行为
也就是说它会根据编译器的不同而变化,完全依赖于C++编译器将代码转换成机器码的实际实现

#include <iostream>void PrintSum(int a, int b)
{std::cout << a << "+" << b << "=" << (a + b) << std::endl;
}int main()
{int value = 0;PrintSum(value++, value++);std::cin.get();
}

在这里插入图片描述
release模式下的常数折叠

C++标准添加了一个从C++17开始的新规则
后缀表达式必须在别的表达式之前被计算

wandbox.org 在线编译网站

C++的参数计算顺序:没有定义

因为c++实际上并没有提供c++规范,并没有提供一个定义,来说明在这种情况下应该发生什么,参数(形参)或实参应该按照什么顺序求值
但如果你提到c++17说了这两件事不能同时做(同时计算)
那就加分了
也就是说,
它们必须一个接一个地完成

但是再说一次,,这个顺序并没有在规范中定义
这意味着你在技术上无法知道计算顺序是什么

四、C++移动语义

左值与右值
移动语义本质上允许我们移动对象

#include <iostream>class String
{
public:String() = default;String(const char* string){printf("Created!\n");m_Size = strlen(string);m_Data = new char[m_Size];memcpy(m_Data, string, m_Size);}String(const String& other){printf("Copied!\n");m_Size = other.m_Size;m_Data = new char[m_Size];memcpy(m_Data, other.m_Data, m_Size);}~String(){delete m_Data;}void Print(){for (uint32_t i = 0; i < m_Size; i++)printf("%c", m_Data[i]);printf("\n");}private:char* m_Data;uint32_t m_Size;
};class Entity
{
public:Entity(const String& name):m_Name(name){}void PrintName(){m_Name.Print();}
private:String m_Name;
};int main()
{Entity entity(String("wm"));entity.PrintName();std::cin.get();
}

在这里插入图片描述

#include <iostream>class String
{
public:String() = default;String(const char* string){printf("Created!\n");m_Size = strlen(string);m_Data = new char[m_Size];memcpy(m_Data, string, m_Size);}String(const String& other){printf("Copied!\n");m_Size = other.m_Size;m_Data = new char[m_Size];memcpy(m_Data, other.m_Data, m_Size);}String(String&& other) noexcept{printf("Moved!\n");m_Size = other.m_Size;m_Data = other.m_Data;other.m_Size = 0;other.m_Data = nullptr;}~String(){printf("Destroyed!\n");delete m_Data;}void Print(){for (uint32_t i = 0; i < m_Size; i++)printf("%c", m_Data[i]);printf("\n");}private:char* m_Data;uint32_t m_Size;
};class Entity
{
public:Entity(const String& name):m_Name(name){}Entity(String&& name):m_Name(name){}void PrintName(){m_Name.Print();}
private:String m_Name;
};int main()
{Entity entity(String("wm"));entity.PrintName();std::cin.get();
}

在这里插入图片描述

#include <iostream>class String
{
public:String() = default;String(const char* string){printf("Created!\n");m_Size = strlen(string);m_Data = new char[m_Size];memcpy(m_Data, string, m_Size);}String(const String& other){printf("Copied!\n");m_Size = other.m_Size;m_Data = new char[m_Size];memcpy(m_Data, other.m_Data, m_Size);}String(String&& other) noexcept{printf("Moved!\n");m_Size = other.m_Size;m_Data = other.m_Data;other.m_Size = 0;other.m_Data = nullptr;}~String(){printf("Destroyed!\n");delete m_Data;}void Print(){for (uint32_t i = 0; i < m_Size; i++)printf("%c", m_Data[i]);printf("\n");}private:char* m_Data;uint32_t m_Size;
};class Entity
{
public:Entity(const String& name):m_Name(name){}Entity(String&& name)// 只修改了此处,输出Moved//:m_Name((String&&)name):m_Name((std::move)name){}void PrintName(){m_Name.Print();}
private:String m_Name;
};int main()
{Entity entity(String("wm"));entity.PrintName();std::cin.get();
}

在这里插入图片描述

Entity(String&& name)
:m_Name(name)
{
}
这里的问题是,此构造函数的参数name应该是一个右值(String&&),所以m_Name(name)应该是调用的String的移动构造函数,为啥要m_Name(std::move(name)) 才行

因为右值引用在进入函数体内的之后,参数类型会变为左值
也就是在函数体内你可以对 String&& val中的 val取&
所以要触发移动语义必须让他变为右值引用,std::move就是干这个转换的
你看std::move的代码 就是干了一个找到源参数类型的static_cast转换
把参数换成了&&类型
所以就能触发后面的移动构造函数

每个表达式都有两种特征:一是类型二是值类别。
很多人迷惑的右值引用为啥是个左值,那是因为右值引用是它的类型,左值是它的值类别。
想理解右值首先要先知道类型和值类别的区别;其次是各个值类别的定义是满足了某种形式它就是那个类别,经常说的能取地址就是左值,否则就是右值,这是定义之上的不严谨经验总结,换句话说,是左值还是右值是强行规定好的,你只需要对照标准看这个表达式满足什么形式就知道它是什么值类别了。
为什么要有这个分类,是为了语义,当一个表达式出现的形式表示它是一个右值,就是告诉编译器,我以后不会再用到这个资源,放心大胆的转移销毁,这就可以做优化,比如节省拷贝之类的。

move的作用是无条件的把表达式转成右值,也就是rvalue_cast,虽然编译器可以推断出左右值,但人有时比编译器“聪明”,人知道这个表达式的值以后我不会用到,所以可以在正常情况下会推成左值的地方强行告诉编译器,我这是个右值,请你按右值的语义来做事。

五、stdmove与移动赋值操作符

移动语义能够将一个对象移动到另一个对象上
move assignment operator(移动赋值运算符)

#include <iostream>class String
{
public:String() = default;String(const char* string){printf("Created!\n");m_Size = strlen(string);m_Data = new char[m_Size];memcpy(m_Data, string, m_Size);}String(const String& other){printf("Copied!\n");m_Size = other.m_Size;m_Data = new char[m_Size];memcpy(m_Data, other.m_Data, m_Size);}String(String&& other) noexcept{printf("Moved!\n");m_Size = other.m_Size;m_Data = other.m_Data;other.m_Size = 0;other.m_Data = nullptr;}String& operator = (String&& other) noexcept{printf("Moved!\n");if (this != &other){delete[] m_Data;m_Size = other.m_Size;m_Data = other.m_Data;other.m_Size = 0;other.m_Data = nullptr;}return *this;}~String(){printf("Destroyed!\n");delete m_Data;}void Print(){for (uint32_t i = 0; i < m_Size; i++)printf("%c", m_Data[i]);printf("\n");}private:char* m_Data;uint32_t m_Size;
};class Entity
{
public:Entity(const String& name):m_Name(name){}Entity(String&& name):m_Name(std::move(name)){}void PrintName(){m_Name.Print();}
private:String m_Name;
};int main()
{Entity entity(String("wm"));entity.PrintName();String apple = "Apple";String dest;//String string = "Hello";//String dest((String&&)string);//String dest = (String&&)string;//String dest(std::move(string));//String dest = std::move(string);//dest.assign(std::move(string));//dest = std::move(dest);apple.Print();dest.Print();dest = std::move(apple);apple.Print();dest.Print();std::cin.get();
}

在这里插入图片描述

int main()
{String apple = "Apple";String dest;std::cout << "Apple: ";apple.Print();std::cout << "Dest: ";dest.Print();dest = std::move(apple);std::cout << "Apple: ";apple.Print();std::cout << "Dest: ";dest.Print();std::cin.get();
}

在这里插入图片描述
总而言之
移动赋值操作符是你想要包含在类中的东西,当你包含一个移动构造函数时,因为它当然是想要将一个对象移动到一个现有的变量中

它基本上是五法则的一部分,还有三法则,五法则包含了所有的新移动语义

注:
C++三法则:如果需要析构函数,则一定需要拷贝构造函数和拷贝赋值操作符C++五法则:为了支持移动语义,又增加了移动构造函数和移动赋值运算符

赋值操作符与使用构造函数的区别:

通过使用这个运算符,它就像我们写.operator=,并像调用函数一样调用它
std:move是你想要将一个对象转换为临时对象时要做的

换句话说,如果你需要把一个已经存在的变量变成临时变量
你可以标记它,表示你可以从这个特定的变量中窃取资源
这使我们能够在现有的变量上执行移动操作

如果你在创建一个新变量,如果是在函数参数中或在移动构造函数中(创建),那么它已经是一个临时变量,这是可以的

但如果你有一个已经存在的变量,比如这个apple的例子
这是一个已经存在的变量,你需要确保使用std:move来将它转换成一个临时变量
这样你就可以使用移动构造函数或移动赋值操作符,从那个变量中获取资源,并进行移动

http://www.dtcms.com/a/575193.html

相关文章:

  • 电竞竞猜网站 建设五大建设是指什么
  • 联合建设官方网站做网站用的书
  • 手机主题如何自己制作网站wordpress精简主题
  • wordpress 用iis建站特价服务器
  • 重庆招聘网站哪个好外加工平台
  • 卡片形式的网站网页设计与制作专业介绍
  • 网站开发业务怎么做南京seo圈子
  • 菏泽营销网站建设公司做车展的网站
  • 用户界面设计报告网站开发技术和seo的联系
  • IEC 62443 标准介绍
  • 湖北做网站价格微信登录wordpress
  • 做设计那个素材网站最好建设银行网站打不开 显示停止工作
  • 泰州网站建设外包企业备案网站服务内容
  • C++基础:Reactor模型设计思想与muduo架构理解
  • 网站推荐软件深圳龙岗高端网站建设
  • 网站建设及验收标准如何自己开发一个软件
  • 怎样提高网站排名网站建设仟首先金手指12
  • 石家庄外贸网站制作ps做网站需注意
  • 慈溪做无痛同济 amp 网站女教师遭网课入侵直播录屏曝光i
  • 设计素材网站有哪些平台免费制作个人网站的软件
  • 专门做海外服装购的网站字体设计的基本原则
  • 清溪镇网站建设对接 网站后台
  • 深圳自建网站网站区分
  • 如何免费建设公司网站碧辉腾乐 网站建设
  • 网页设计新手制作的网站代码网站建设流程是什么意思
  • 网站怎么做视频教程wordpress添加订阅教程
  • 佛山 做网站公司有哪些哪一个军事网站做的比较好
  • 怎么找一家公司的网站代刷网自助建站系统
  • raf节流
  • 【SOA仿真】SOA增益饱和特性仿真3