网站开发合肥wordpress页面加载很慢

张小明 2026/1/12 11:48:52
网站开发合肥,wordpress页面加载很慢,哪个网站可以做医学基础知识题,uc投放广告网站要自己做吗作用#xff1a;C11中引用了右值引用和移动语义#xff0c;可以避免无谓的复制#xff0c;提高了程序性能。 1. 什么是左值、右值 可以从2个角度判断#xff1a; 左值可以取地址、位于等号左边#xff1b; 而右值没法取地址#xff0c;位于等号右边。 int a 6; a可…作用C11中引用了右值引用和移动语义可以避免无谓的复制提高了程序性能。1. 什么是左值、右值可以从2个角度判断左值可以取地址、位于等号左边而右值没法取地址位于等号右边。int a 6;a可以通过 取地址位于等号左边所以a是左值。6位于等号右边6没法通过 取地址所以6是个右值。再举个复杂点的例子struct A { A(int a 0) { a_ a; } int a_; }; A a A();同样的a可以通过 取地址位于等号左边所以a是左值。A()是个临时值没法通过 取地址位于等号右边所以A()是个右值。可见左右值的概念很清晰有地址的变量就是左值没有地址的字面值、临时值就是右值。2.什么是左值引用、右值引用引用本质是别名可以通过引用修改变量的值传参时传引用可以避免拷贝。2.1 左值引用左值引用能指向左值不能指向右值的就是左值引用int a 5; int ref_a a; // 左值引用指向左值编译通过 int ref_a 5; // 左值引用指向了右值会编译失败引用是变量的别名由于右值没有地址没法被修改所以左值引用无法指向右值。但是const左值引用是可以指向右值的const int ref_a 5; // 编译通过const左值引用不会修改指向值因此可以指向右值这也是为什么要使用const 作为函数参数的原 因之一如std::vector的push_backvoid push_back (const value_type val);如果没有constvec.push_back(5)这样的代码就无法编译通过。2.2 右值引用再看下右值引用右值引用的标志是 顾名思义右值引用专门为右值而生可以指向右值不能指向左值int ref_a_right 5; // ok int a 5; int ref_a_left a; // 编译不过右值引用不可以指向左值 ref_a_right 6; // 右值引用的用途可以修改右值2.3 对左右值引用本质的讨论2.3.1 右值引用有办法指向左值吗有办法使用 std::move int a 5; // a是个左值 int ref_a_left a; // 左值引用指向左值 int ref_a_right std::move(a); // 通过std::move将左值转化为右值可以被右值引用指向 cout a; // 打印结果5在上边的代码里看上去是左值a通过std::move移动到了右值ref_a_right中那是不是a里边就没有值 了并不是打印出a的值仍然是5。std::move是一个非常有迷惑性的函数不理解左右值概念的人们往往以为它能把一个变量里的内容移动到另一个变量但事实上std::move移动不了什么唯一的功能是把左值强制转化为右值让右值引用可以指向左 值。其实现等同于一个类型转换 static_cast(lvalue) 。 所以单纯的std::move(xxx) 不会有性能提升。同样的右值引用能指向右值本质上也是把右值提升为一个左值并定义一个右值引用通过std::move 指向该左值int ref_a 5; ref_a 6; 等同于以下代码 int temp 5; int ref_a std::move(temp); ref_a 6; // 此时temp等于62.3.2 左值引用、右值引用本身是左值还是右值被声明出来的左、右值引用都是左值。 因为被声明出的左右值引用是有地址的也位于等号左边。仔细看下边代码// 形参是个右值引用 void change(int right_value) { right_value 8; } int main() { int a 5; // a是个左值 int ref_a_left a; // ref_a_left是个左值引用 int ref_a_right std::move(a); // ref_a_right是个右值引用 change(a); // 编译不过a是左值change参数要求右值 change(ref_a_left); // 编译不过左值引用ref_a_left本身也是个左值 change(ref_a_right); // 编译不过右值引用ref_a_right本身也是个左值 change(std::move(a)); // 编译通过 change(std::move(ref_a_right)); // 编译通过 change(std::move(ref_a_left)); // 编译通过 change(5); // 当然可以直接接右值编译通过 cout a ; cout ref_a_left ; cout ref_a_right; // 打印这三个左值的地址都是一样的 }看完后可能有个问题std::move会返回一个右值引用int 它是左值还是右值呢 从表达式int ref std::move(a)来看右值引用ref指向的必须是右值所以move返回的int 是个右值。 所以右值引用既可能是左值又可能是右值吗 确实如此右值引用既可以是左值也可以是右值如果 有名称则为左值否则是右值。或者说作为函数返回值的 是右值直接声明出来的 是左值。 这同样也符合前面章节对左值 右值的判定方式其实引用和普通变量是一样的int ref std::move(a)和int a 5没有什 么区别等号左边就是左值右边就是右值。最后从上述分析中我们得到如下结论1. 从性能上讲左右值引用没有区别传参使用左右值引用都可以避免拷贝。2. 右值引用可以直接指向右值也可以通过std::move指向左值而左值引用只能指向左值(const左 值引用也能指向右值)。3. 作为函数形参时右值引用更灵活。虽然const左值引用也可以做到左右值都接受但它无法修 改有一定局限性。void f(const int n) { n 1; // 编译失败const左值引用不能修改指向变量 } void f2(int n) { n 1; // ok } int main() { f(5); f2(5); }3 右值引用和std::move使用场景std::move 只是类型转换工具不会对性能有好处3.1 右值引用优化性能避免深拷贝浅拷贝重复释放 对于含有堆内存的类我们需要提供深拷贝的拷贝构造函数如果使用默认构造函数会导致堆内存的 重复删除比如下面的代码//2-3-1-memory #includeiostream using namespace std; class A { public: A() :m_ptr(new int(0)) { cout constructor A endl; } ~A(){ cout destructor A, m_ptr: m_ptr endl; delete m_ptr; m_ptr nullptr; } private: int* m_ptr; }; // 为了避免返回值优化此函数故意这样写 A Get(bool flag) { A a; A b; cout ready return endl; if (flag) return a; else return b; } int main() { { A a Get(false); // 运行报错 } cout main finish endl; return 0; }打印constructor Aconstructor A // 默认的拷贝构造函数没有打印ready returndestructor A, m_ptr:0xf87af8destructor A, m_ptr:0xf87ae8destructor A, m_ptr:0xf87af8main finish深拷贝构造函数在上面的代码中默认构造函数是浅拷贝main函数的 a 和Get函数的 b 会指向同一个指针 m_ptr在 析构的时候会导致重复删除该指针。正确的做法是提供深拷贝的拷贝构造函数比如下面的代码//2-3-1-memory2 #include iostream using namespace std; class A { public: A() :m_ptr(new int(0)) { cout constructor A endl; } A(const A a) :m_ptr(new int(*a.m_ptr)) { cout copy constructor A endl; } ~A(){ cout destructor A, m_ptr: m_ptr endl; delete m_ptr; m_ptr nullptr; } private: int* m_ptr; }; // 为了避免返回值优化此函数故意这样写 A Get(bool flag) { A a; A b; cout ready return endl; if (flag) return a; else return b; } int main() { { A a Get(false); // 正确运行 } cout main finish endl; return 0; }运行结果constructor Aconstructor Aready returncopy constructor Adestructor A, m_ptr:0xea7af8destructor A, m_ptr:0xea7ae8destructor A, m_ptr:0xea7b08main finish移动构造函数这样就可以保证拷贝构造时的安全性但有时这种拷贝构造却是不必要的比如上面代码中的拷贝构造 就是不必要的。上面代码中的 Get 函数会返回临时变量然后通过这个临时变量拷贝构造了一个新的对 象 b临时变量在拷贝构造完成之后就销毁了如果堆内存很大那么这个拷贝构造的代价会很大 带来了额外的性能损耗。有没有办法避免临时对象的拷贝构造呢答案是肯定的。看下面的代码//2-3-1-memory3 #include iostream using namespace std; class A { public: A() :m_ptr(new int(0)) { cout constructor A endl; } A(const A a) :m_ptr(new int(*a.m_ptr)) { cout copy constructor A endl; } // 移动构造函数可以浅拷贝 A(A a) :m_ptr(a.m_ptr) { a.m_ptr nullptr; // 为防止a析构时delete data提前置空其m_ptr cout move constructor A endl; } ~A(){ cout destructor A, m_ptr: m_ptr endl; if(m_ptr) delete m_ptr; } private: int* m_ptr; }; // 为了避免返回值优化此函数故意这样写 A Get(bool flag) { A a; A b; cout ready return endl; if (flag) return a; else return b; } int main() { { A a Get(false); // 正确运行 } cout main finish endl; return 0; }运行结果constructor Aconstructor Aready returnmove constructor A destructor A, m_ptr:0destructor A, m_ptr:0xfa7ae8destructor A, m_ptr:0xfa7af8main finish上面的代码中没有了拷贝构造取而代之的是移动构造 Move Construct。从移动构造函数的实现 中可以看到它的参数是一个右值引用类型的参数 A这里没有深拷贝只有浅拷贝这样就避免了 对临时对象的深拷贝提高了性能。这里的 A 用来根据参数是左值还是右值来建立分支如果是临时 值则会选择移动构造函数。移动构造函数只是将临时对象的资源做了浅拷贝不需要对其进行深拷 贝从而避免了额外的拷贝提高性能。这也就是所谓的移动语义 move 语义右值引用的一个重要目的是用来支持移动语义的。移动语义可以将资源堆、系统对象等通过浅拷贝方式从一个对象转移到另一个对象这样能够减少 不必要的临时对象的创建、拷贝以及销毁可以大幅度提高 C 应用程序的性能消除临时对象的维护 创建和销毁对性能的影响。3.2 移动(move )语义move是将对象的状态或者所有权从一个对象转移到另一个对象只是转义没有内存拷贝。要move语义起作用核心在于需要对应类型的构造函数支持。//2-3-2-move #include iostream #include vector #include cstdlio #include cstdlib #include string.h using namespace std; class MyString { private: char* m_data; size_t m_len; void copy_data(const char *s) { m_data new char[m_len1]; memcpy(m_data, s, m_len); m_data[m_len] \0; } public: MyString() { m_data NULL; m_len 0; } MyString(const char* p) { m_len strlen (p); copy_data(p); } MyString(const MyString str) { m_len str.m_len; copy_data(str.m_data); std::cout Copy Constructor is called! source: str.m_data std::endl; } MyString operator(const MyString str) { if (this ! str) { m_len str.m_len; copy_data(str.m_data); } std::cout Copy Assignment is called! source: str.m_data std::endl; return *this; } // 用c11的右值引用来定义这两个函数 MyString(MyString str) { std::cout Move Constructor is called! source: str.m_data std::endl; m_len str.m_len; m_data str.m_data; //避免了不必要的拷贝 str.m_len 0; str.m_data NULL; } MyString operator(MyString str) { std::cout Move Assignment is called! source: str.m_data std::endl; if (this ! str) { m_len str.m_len; m_data str.m_data; //避免了不必要的拷贝 str.m_len 0; str.m_data NULL; } return *this; } virtual ~MyString() { if (m_data) free(m_data); } }; int main() { MyString a; a MyString(Hello); // Move Assignment MyString b a; // Copy Constructor MyString c std::move(a); // Move Constructor is called! 将左值转为右值 std::vector vec; vec.push_back(MyString(World)); // Move Constructor is called! return 0; }有了右值引用和转移语义我们在设计和实现类时对于需要动态申请大量资源的类应该设计右值引 用的拷贝构造函数和赋值函数以提高应用程序的效率。3.3 forward 完美转发forward 完美转发实现了参数在传递过程中保持其值属性的功能即若是左值则传递之后仍然是左 值若是右值则传递之后仍然是右值。现存在一个函数Templateclass T void func(T val);根据前面所描述的这种引用类型既可以对左值引用亦可以对右值引用。但要注意引用以后这个val值它本质上是一个左值看下面例子int a 10; int b a; //错误注意这里a是一个右值引用但其本身a也有内存名字所以a本身是一个左值再用右值引用引用a这 是不对的。因此我们有了std::forward()完美转发这种T val中的val是左值但如果我们用std::forward (val) 就会按照参数原来的类型转发int a 10; int b std::forwardint(a);这样是正确的通过范例2-3-2-forward1巩固下知识// 2-3-2-forward1 #include iostream using namespace std; templateclass T void Print(T t) { cout L t endl; } templateclass T void Print(T t) { cout R t endl; } templateclass T void Print(T t) { Print(t); Print(std::move(t)); Print(std::forwardT(t)); } int main() { cout -- func(1) endl; func(1); int x 10; int y 20; cout \n-- func(x) endl; func(x); // x本身是左值 cout \n-- func(std::forwardint(y)) endl; func(std::forwardint(y)); ////T为int以右值方式转发y cout \n-- func(std::forwardint(y)) endl; func(std::forwardint(y)); cout \n-- func(std::forwardint(y)) endl; func(std::forwardint(y)); return 0; }运行结果-- func(1)L1R1R1-- func(x)L10R10L10-- func(std::forward(y))L20R20R20-- func(std::forwardint(y))L20R20L20解释func(1)由于1是右值所以未定的引用类型Tv被一个右值初始化后变成了一个右值引用但是在 func()函数体内部调用PrintT(v) 时v又变成了一个左值因为在std::forward里它已经变成了一个具 名的变量所以它是一个左值因此示例测试结果第一个PrintT被调用打印出“L1调用PrintTstd::forward(v)时由于std::forward会按参数原来的类型转发因此它还是一个右值 这里已经发生了类型推导所以这里的T不是一个未定的引用类型会调用void PrintTTt函 数打印 “R1”.调用PrintT(std::move(v))是将v变成一个右值v本身也是右值因此它将输出”R1func(x)未定的引用类型Tv被一个左值初始化后变成了一个左值引用因此在调用 PrintT(std::forward(v))时它会被转发到void PrintTTt.forward将左值转换为右值MyString str1 hello; MyString str2(str1); MyString str3 Fun(); MyString str4 move(str2); MyString str5(forward(str3));参考链接0voice · GitHub
版权声明:本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

长春网站制作方案定制半夜一分快三app推荐直播下载

LobeChat能否生成二维码?实用小功能上线 在智能助手越来越“能干”的今天,我们对AI的期待早已不再局限于回答问题。用户希望它能真正帮自己完成任务——比如发个链接时顺手生成一个二维码,扫码直达,省去复制粘贴的麻烦。这种看似微…

张小明 2025/12/26 9:36:06 网站建设

怎么做免费的宣传网站有后台的网站如何建设

1.Rufus适用于台式机装系统(MBR格式,一般台式机是MBR的,legacy模式), Rufus官网 即使是iso镜像,制作完U盘之后,UEFI模式的笔记本需要打开legacy模式才能识别到分区,但是台式机兼容性…

张小明 2025/12/26 9:36:06 网站建设

免费响应式模板网站模板搭建网站合同

如何用3步完成MCP服务器代码质量检测:新手终极指南 【免费下载链接】awesome-mcp-servers A collection of MCP servers. 项目地址: https://gitcode.com/GitHub_Trending/aweso/awesome-mcp-servers 你是否担心自己的MCP服务器存在隐藏bug却无从下手&#x…

张小明 2026/1/1 14:21:14 网站建设

手机企业网站程序网站qq 微信分享怎么做的

第一章:MCP量子编程认证概述MCP量子编程认证(Microsoft Certified Professional Quantum Programming Certification)是微软推出的一项面向量子计算开发者的专业资格认证,旨在评估开发者在Q#语言、量子算法设计及Azure Quantum平台…

张小明 2025/12/26 9:36:05 网站建设

诚信网站认证99idc三原县城乡建设局网站

导语 【免费下载链接】Ming-flash-omni-Preview 项目地址: https://ai.gitcode.com/hf_mirrors/inclusionAI/Ming-flash-omni-Preview 2025年12月,Inclusion AI发布开源全模态大模型Ming-flash-omni Preview,以100B总参数、6B动态激活的稀疏混合…

张小明 2025/12/26 9:36:07 网站建设

小型网站开发成本做公司网站的南宁公司

3分钟快速上手:BongoCat终极快捷键定制完全指南 【免费下载链接】BongoCat 让呆萌可爱的 Bongo Cat 陪伴你的键盘敲击与鼠标操作,每一次输入都充满趣味与活力! 项目地址: https://gitcode.com/gh_mirrors/bong/BongoCat 想要让可爱的B…

张小明 2026/1/9 20:48:39 网站建设