search
HomeBackend DevelopmentC#.Net TutorialA brief analysis of rvalue references, transfer semantics and perfect forwarding in C++11

1. Lvalues ​​and rvalues:

C++ has no standard definitions for lvalues ​​and rvalues, but there is a widely recognized saying: those with addresses, names, and non-temporary ones are lvalue; one that cannot take an address, has no name, and is temporary is an rvalue.

It can be seen that immediate data, the value returned by the function, etc. are all rvalues; instead of anonymous objects (including variables), the values ​​returned by the function References, const objects, etc. are all lvalues.

Essentially understood, creation and destruction are controlled by the compiler behind the scenes. Programmers can only ensure that what is valid in this line of code is rvalues ​​(including immediate numbers). ); and those created by users, whose lifetime can be known through scoping rules, are lvalues ​​(including references to local variables returned by functions and const objects), for example:

int& foo(){int tmp; return tmp;}
 
int fooo(){int tmp; return tmp;}
 
int a=10;
 
const int b;
 
int& temp=foo();//虽然合法,但temp引用了一个已经不存在的对象
 
int tempp=fooo();

In the above code, a, temp and foo() are all non-constant lvalues, b is a constant lvalue, fooo() is a non-constant rvalue, and 10 is a constant rvalue. There is one thing to pay special attention to: The reference returned is an lvalue (can take an address)!

Generally speaking, the compiler does not allow changes to rvalues ​​(because the lifetime of the rvalue is not controlled by the programmer, even if the rvalue is changed, it may not be usable), especially for built-in type objects. , but C++ allows the use of rvalue objects to call member functions. Although this is allowed, it is best not to do so for the same reason.

2. Rvalue reference:

Rvalue reference The representation method is

Datatype&& variable

Rvalue reference is a new feature of C++11, so the reference of C++98 is an lvalue reference. Rvalue reference is used to bind When bound to an rvalue, the lifetime of the rvalue that would have been destroyed after being bound to the rvalue will be extended to the lifetime of the rvalue reference bound to it. The existence of the rvalue reference is not to replace the lvalue reference. Instead, make full use of the construction of rvalues ​​(especially temporary objects) to reduce object construction and destruction operations to improve efficiency. For example, for the following functions:

(Demo是一个类)
Demo foo(){
  Demo tmp;
  return tmp;
}

Under the premise that the compiler does not perform RVO (return value optimization) optimization, the following operations are performed:

Demo x=foo();

The constructor (tmp's, x, temporary object), correspondingly the destructor will be called three times when the object is destroyed, and if rvalue reference is used:

Demo&& x=foo();

Then there is no need to construct x. The temporary object that was originally going to be destroyed will also have its lifetime extended to the same as x due to the binding of x (it can be understood that x gives the temporary object a legal status: a name ), the efficiency needs to be improved (the price is that tmp needs to occupy 4 bytes of space, but this is trivial).

Binding rules for rvalue references and lvalue references:

Constant left Value references can be bound to constant and non-constant lvalues, constants and non-constant rvalues;

Non-constant lvalue references can only be bound to non-constant lvalues;

Non-constant right values Value references can only be bound to non-const rvalues ​​(vs2013 can also be bound to constant rvalues); It only exists for the completeness of semantics, and constant lvalue references can achieve its role).

Although it can be seen from the binding rules that constant lvalue references can also be bound to rvalues, it is obviously not You can change the value of an rvalue by using an rvalue reference to achieve transfer semantics. Because an rvalue reference usually changes the bound rvalue, the bound rvalue cannot be const.

Note :Rvalue references are lvalues!

3. Move semantics:

One of the purposes of rvalue references being introduced is to implement transfer semantics. Transfer semantics can move resources (heap , system objects, etc.) is transferred from one object (usually an anonymous temporary object) to another object, thereby reducing object construction and destruction operations and improving program efficiency (this has been explained in the example of 2). Transfer semantics It is opposite to copy semantics. As can be seen from transfer semantics, in fact, transfer semantics is not a new concept. It has actually been used in the language and library of C++98/03, such as in some cases. The omission of the copy constructor (copy constructor elision in some contexts), the copy of the smart pointer (auto_ptr "copy"), the splicing of the linked list (list::splice) and the replacement of the container (swap on containers), etc., are just not unified yet. Syntax and semantic support

Although ordinary functions and operators can also use rvalue references to implement transfer semantics (such as the example in 2), transfer semantics are usually implemented through transfer constructors and transfer assignment operators. The prototype of the transfer constructor is Classname(Typename&&), while the prototype of the copy constructor is Classname(const Typename&). The transfer constructor will not be automatically generated by the compiler and needs to be defined by yourself. Only defining the transfer constructor will not affect compilation. The constructor generates a copy constructor. If the passed parameter is an lvalue, the copy constructor is called. Otherwise, the transfer constructor is called.

For example:

class Demo{
 
public:
 
  Demo():p(new int[10000]{};
 
  Demo(Demo&& lre):arr(lre.arr),size(lra.size){lre.arr=NULL;}//转移构造函数
 
  Demo(const Demo& lre):arr(new int[10000]),size(arr.size){
 
    for(int cou=0;cou<10000;++cou)
 
      arr[cou]=lew.arr[cou];
 
  }
 
private:
 
  int size;
 
  int* arr;
 
}

    从以上代码可以看出,拷贝构造函数在堆中重新开辟了一个大小为10000的int型数组,然后每个元素分别拷贝,而转移构造函数则是直接接管参数的指针所指向的资源,效率搞下立判!需要注意的是转移构造函数实参必须是右值,一般是临时对象,如函数的返回值等,对于此类临时对象一般在当行代码之后就被销毁,而采用转移构造函数可以延长其生命期,可谓是物尽其用,同时有避免了重新开辟数组.对于上述代码中的转移构造函数,有必要详细分析一下:

Demo(Demo&& lre):arr(lre.arr),size(lre.size)({lre.arr=NULL;}

   

lre是一个右值引用,通过它间接访问实参(临时对象)的资源来完成资源转移,lre绑定的对象(必须)是右值,但lre本身是左值;

因为lre是函数的局部对象,”lre.arr=NULL"必不可少,否则函数结尾调用析构函数销毁lre时仍然会将资源释放,转移的资源还是被系统收回.

4. move()函数

    3中的例子并非万能,Demo(Demo&& lre)的实参必须是右值,有时候一个左值即将到达生存期,但是仍然想要使用转移语义接管它的资源,这时就需要move函数.

    std::move函数定义在标准库中,它的作用是将左值强行转化为右值使用,从实现上讲,std:move等同于static_cast(lvalue) ,由此看出,被转化的左值本身的生存期和左值属性并没有被改变,这类似于const_cast函数.因此被move的实参应该是即将到达生存期的左值,否则的话可能起到反面效果.

5. 完美转发(perfect forwarding)

    完美转发指的是将一组实参"完美"地传递给形参,完美指的是参数的const属性与左右值属性不变,例如在进行函数包装的时候,func函数存在下列重载:

void func(const int);
void func(int);
void func(int&&);

   

如果要将它们包装到一个函数cover内,以实现:

void cover(typename para){
  func(para);
}

   

使得针对不同实参能在cover内调用相应类型的函数,似乎只能通过对cover进行函数重载,这使代码变得冗繁,另一种方法就是使用函数模板,但在C++ 11之前,实现该功能的函数模板只能采用值传递,如下:

template<typename T>
void cover(T para){
  ...
  func(para);
  ...
}

   

但如果传递的是一个相当大的对象,又会造成效率问题,要通过引用传递实现形参与实参的完美匹配(包裹const属性与左右值属性的完美匹配),就要使用C++ 11 新引入的引用折叠规则:

函数形参       T的类型         推导后的函数形参

T&               A&                A&
T&               A&&              A&
T&&             A&                A&
T&&             A&&              A&&

 因此,对于前例的函数包装要求,采用以下模板就可以解决:

template<typename T>
void cover(T&& para){
  ...
  func(static_cast<T &&>(para));
  ...
}

如果传入的是左值引用,转发函数将被实例化为:

void func(T& && para){
 
  func(static_cast<T& &&>(para));
 
}

应用引用折叠,就为:

void func(T& para){
 
  func(static_cast<T&>(para));
 
}

如果传入的是右值引用,转发函数将被实例化为:

void func(T&& &¶){
 
   func(static_cast<T&& &&>(para));
}

应用引用折叠,就是:

void func(T&& para){
 
  func(static_cast<T&&>(para));
 
}

对于以上的static_cast ,实际上只在para被推导为右值引用的时候才发挥作用,由于para是左值(右值引用是左值),因此需要将它转为右值后再传入func内,C++ 11在定义了一个std::forward函数来实现以上行为,

所以最终版本

template<typename T>
 
void cover(T&& para){
 
  func(forward(forward<T>(para)));
 
}

std::forward的实现与static_cast(para)稍有不同

std::forward函数的用法为forward(para) , 若T为左值引用,para将被转换为T类型的左值,否则para将被转换为T类型右值

总结

以上就是关于C++11中右值引用、转移语义和完美转发的全部内容,这篇文章介绍的很详细,希望对大家的学习工作能有所帮助。

更多浅析C++11中的右值引用、转移语义和完美转发相关文章请关注PHP中文网!

Statement
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Mastering C# .NET Design Patterns: From Singleton to Dependency InjectionMastering C# .NET Design Patterns: From Singleton to Dependency InjectionMay 09, 2025 am 12:15 AM

Design patterns in C#.NET include Singleton patterns and dependency injection. 1.Singleton mode ensures that there is only one instance of the class, which is suitable for scenarios where global access points are required, but attention should be paid to thread safety and abuse issues. 2. Dependency injection improves code flexibility and testability by injecting dependencies. It is often used for constructor injection, but it is necessary to avoid excessive use to increase complexity.

C# .NET in the Modern World: Applications and IndustriesC# .NET in the Modern World: Applications and IndustriesMay 08, 2025 am 12:08 AM

C#.NET is widely used in the modern world in the fields of game development, financial services, the Internet of Things and cloud computing. 1) In game development, use C# to program through the Unity engine. 2) In the field of financial services, C#.NET is used to develop high-performance trading systems and data analysis tools. 3) In terms of IoT and cloud computing, C#.NET provides support through Azure services to develop device control logic and data processing.

C# .NET Framework vs. .NET Core/5/6: What's the Difference?C# .NET Framework vs. .NET Core/5/6: What's the Difference?May 07, 2025 am 12:06 AM

.NETFrameworkisWindows-centric,while.NETCore/5/6supportscross-platformdevelopment.1).NETFramework,since2002,isidealforWindowsapplicationsbutlimitedincross-platformcapabilities.2).NETCore,from2016,anditsevolutions(.NET5/6)offerbetterperformance,cross-

The Community of C# .NET Developers: Resources and SupportThe Community of C# .NET Developers: Resources and SupportMay 06, 2025 am 12:11 AM

The C#.NET developer community provides rich resources and support, including: 1. Microsoft's official documents, 2. Community forums such as StackOverflow and Reddit, and 3. Open source projects on GitHub. These resources help developers improve their programming skills from basic learning to advanced applications.

The C# .NET Advantage: Features, Benefits, and Use CasesThe C# .NET Advantage: Features, Benefits, and Use CasesMay 05, 2025 am 12:01 AM

The advantages of C#.NET include: 1) Language features, such as asynchronous programming simplifies development; 2) Performance and reliability, improving efficiency through JIT compilation and garbage collection mechanisms; 3) Cross-platform support, .NETCore expands application scenarios; 4) A wide range of practical applications, with outstanding performance from the Web to desktop and game development.

Is C# Always Associated with .NET? Exploring AlternativesIs C# Always Associated with .NET? Exploring AlternativesMay 04, 2025 am 12:06 AM

C# is not always tied to .NET. 1) C# can run in the Mono runtime environment and is suitable for Linux and macOS. 2) In the Unity game engine, C# is used for scripting and does not rely on the .NET framework. 3) C# can also be used for embedded system development, such as .NETMicroFramework.

The .NET Ecosystem: C#'s Role and BeyondThe .NET Ecosystem: C#'s Role and BeyondMay 03, 2025 am 12:04 AM

C# plays a core role in the .NET ecosystem and is the preferred language for developers. 1) C# provides efficient and easy-to-use programming methods, combining the advantages of C, C and Java. 2) Execute through .NET runtime (CLR) to ensure efficient cross-platform operation. 3) C# supports basic to advanced usage, such as LINQ and asynchronous programming. 4) Optimization and best practices include using StringBuilder and asynchronous programming to improve performance and maintainability.

C# as a .NET Language: The Foundation of the EcosystemC# as a .NET Language: The Foundation of the EcosystemMay 02, 2025 am 12:01 AM

C# is a programming language released by Microsoft in 2000, aiming to combine the power of C and the simplicity of Java. 1.C# is a type-safe, object-oriented programming language that supports encapsulation, inheritance and polymorphism. 2. The compilation process of C# converts the code into an intermediate language (IL), and then compiles it into machine code execution in the .NET runtime environment (CLR). 3. The basic usage of C# includes variable declarations, control flows and function definitions, while advanced usages cover asynchronous programming, LINQ and delegates, etc. 4. Common errors include type mismatch and null reference exceptions, which can be debugged through debugger, exception handling and logging. 5. Performance optimization suggestions include the use of LINQ, asynchronous programming, and improving code readability.

See all articles

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

SublimeText3 Linux new version

SublimeText3 Linux new version

SublimeText3 Linux latest version

WebStorm Mac version

WebStorm Mac version

Useful JavaScript development tools

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

Powerful PHP integrated development environment

MantisBT

MantisBT

Mantis is an easy-to-deploy web-based defect tracking tool designed to aid in product defect tracking. It requires PHP, MySQL and a web server. Check out our demo and hosting services.

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use