日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪(fǎng)問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

C++11中rvalue references的使用

發(fā)布時(shí)間:2023/11/27 51 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C++11中rvalue references的使用 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Rvalue references are a feature of C++ that was added with the C++11 standard. The syntax of an rvalue reference is to add && after a type.

為了支持移動(dòng)操作,C++11引入了一種新的引用類(lèi)型----右值引用(rvalue reference)。所謂右值引用就是必須綁定到右值的引用。通過(guò)&&而不是&來(lái)獲得右值引用。右值引用有一個(gè)重要的性質(zhì)----只能綁定到一個(gè)將要銷(xiāo)毀的對(duì)象。因此,可以自由地將一個(gè)右值引用的資源”移動(dòng)”到另一個(gè)對(duì)象中。
一般而言,一個(gè)左值表達(dá)式表示的是一個(gè)對(duì)象的身份,而一個(gè)右值表達(dá)式表示的是對(duì)象的值。
類(lèi)似任何引用,一個(gè)右值引用也不過(guò)是某個(gè)對(duì)象的另一個(gè)名字而已。對(duì)于常規(guī)引用(為了與右值引用區(qū)分開(kāi)來(lái),可以稱(chēng)之為左值引用(lvalue reference)),不能將其綁定到要求轉(zhuǎn)換的表達(dá)式、字面常量或是返回右值的表達(dá)式。右值引用有著完全相反的綁定特性:可以將一個(gè)右值引用綁定到這類(lèi)表達(dá)式上,但不能將一個(gè)右值引用直接綁定到一個(gè)左值上。
返回左值引用的函數(shù),連同賦值、下標(biāo)、解引用和前置遞增/遞減運(yùn)算符,都是返回左值得表達(dá)式的例子。可以將一個(gè)左值引用綁定到這類(lèi)表達(dá)式的結(jié)果上。
返回非引用類(lèi)型的函數(shù),連同算術(shù)、關(guān)系、位以及后置遞增/遞減運(yùn)算符,都生成右值。不能將一個(gè)左值引用綁定到這類(lèi)表達(dá)式上,但可以將一個(gè)const的左值引用或者一個(gè)右值引用綁定到這類(lèi)表達(dá)式上。
左值持久,右值短暫:左值有持久的狀態(tài),而右值要么是字面常量,要么是在表達(dá)式求值過(guò)程中創(chuàng)建的臨時(shí)對(duì)象。
由于右值引用只能綁定到臨時(shí)對(duì)象,可知:所引用的對(duì)象將要被銷(xiāo)毀;該對(duì)象沒(méi)有其它用戶(hù)。這兩個(gè)特性意味著,使用右值引用的代碼可以自由地接管所引用的對(duì)象的資源。
變量是左值:變量可以看作只有一個(gè)運(yùn)算對(duì)象而沒(méi)有運(yùn)算符的表達(dá)式。
變量是左值,因此不能將一個(gè)右值引用直接綁定到一個(gè)變量上,即使這個(gè)變量是右值引用類(lèi)型也不行。
雖然不能就將一個(gè)右值引用直接綁定到一個(gè)左值上,但可以顯示地將一個(gè)左值轉(zhuǎn)換為對(duì)應(yīng)的右值引用類(lèi)型。還可以通過(guò)調(diào)用一個(gè)名為move的新標(biāo)準(zhǔn)庫(kù)函數(shù)來(lái)獲得綁定到左值上的右值引用,此函數(shù)定義在頭文件utility中。move調(diào)用告訴編譯器:有一個(gè)左值,但希望像一個(gè)右值一樣處理它。在調(diào)用move之后,我們不能對(duì)移后源對(duì)象的值做任何假設(shè)。
我們可以銷(xiāo)毀一個(gè)移后源對(duì)象,也可以賦予它新值,但不能使用一個(gè)移后源對(duì)象的值。

In C++, there are rvalues and lvalues. An lvalue is an expression whose address can be taken,a locator value--essentially, an lvalue provides a (semi)permanent piece of memory. rvalues are not lvalues. An expression is an rvalue if it results in a temporary object.

Every C++ expression is either an lvalue or an rvalue. An lvalue refers to an object that persists beyond a single expression. You can think of an lvalue as an object that has a name. All variables, including nonmodifiable (const) variables, are lvalues. An rvalue is a temporary value that does not persist beyond the expression that uses it.

an "rvalue reference", that will let you bind a mutable reference to an rvalue, but not an lvalue. In other words, rvalue references are perfect for detecting if a value is temporary object or not. Rvalue references use the && syntax instead of just &, and can be const and non-const, just like lvalue references, although you'll rarely see a const rvalue reference.

Rvalue references solve at least two problems: Implementing move semantics; Perfect forwarding.

The original definition of lvalues and rvalues from the earliest days of C is as follows: An lvalue is an expression e that may appear on the left or on the right hand side of an assignment, whereas an rvalue is an expression that can only appear on the right hand side of an assignment.

If X is any type, then X&& is called an rvalue reference to X. For better distinction, the ordinary reference X& is now also called an lvalue reference.

rvalue references enable us to distinguish an lvalue from an rvalue.

In C++11,however, the rvalue reference lets us bind a mutable reference to an rvalue,but not an lvalue. In other words, rvalue references are perfect for detecting whether a value is a temporary object or not.

Important rvalue reference properties:

(1)、For overload resolution, lvalues prefer binding to lvalue references and rvalues prefer binding to rvalue references. Hence why temporaries prefer invoking a move constructor / move assignment operator over a copy constructor / assignment operator.

(2)、rvalue references will implicitly bind to rvalues and to temporaries that are the result of an implicit conversion. i.e. float f = 0f; int&& i = f; is well formed because float is implicitly convertible to int; the reference would be to a temporary that is the result of the conversion.

(3)、Named rvalue references are lvalues. Unnamed rvalue references are rvalues. This is important to understand why the std::move call is necessary in: foo&& r= foo(); foo f = std::move(r).

Rvalue references enable you to distinguish an lvalue from an rvalue. Lvalue references and rvalue references are syntactically and semantically similar,but they follow somewhat different rules.

右值引用是C++11中最重要的新特性之一,它解決了C++中大量的歷史遺留問(wèn)題,使C++標(biāo)準(zhǔn)庫(kù)的實(shí)現(xiàn)在多種場(chǎng)景下消除了不必要的額外開(kāi)銷(xiāo)(如std::vector, std::string),也使得另外一些標(biāo)準(zhǔn)庫(kù)(如std::unique_ptr, std::function)成為可能。即使你并不直接使用右值引用,也可以通過(guò)標(biāo)準(zhǔn)庫(kù),間接從這一新特性中受益。

右值引用的意義通常解釋為兩大作用:移動(dòng)語(yǔ)義和完美轉(zhuǎn)發(fā)。

右值引用可以使我們區(qū)分表達(dá)式的左值和右值。

右值引用它實(shí)現(xiàn)了移動(dòng)語(yǔ)義(Move Sementics)和完美轉(zhuǎn)發(fā)(Perfect Forwarding)。它的主要目的有兩個(gè)方面:(1)、消除兩個(gè)對(duì)象交互時(shí)不必要的對(duì)象拷貝,節(jié)省運(yùn)算存儲(chǔ)資源,提高效率;(2)、能夠更簡(jiǎn)潔明確地定義泛型函數(shù)。

右值引用主要就是解決一個(gè)拷貝效率低下的問(wèn)題,因?yàn)獒槍?duì)于右值,或者打算更改的左值,我們可以采用類(lèi)似與auto_ptr的move(移動(dòng))操作,大大的提高性能(move semantics)。另外,C++的模板推斷機(jī)制為參數(shù)T&&做了一個(gè)例外規(guī)則,讓左值和右值的識(shí)別和轉(zhuǎn)向(forward)非常簡(jiǎn)單,幫助我們寫(xiě)出高效并且簡(jiǎn)捷的泛型代碼(perfect forwarding)。

左值的聲明符號(hào)為”&”, 為了和左值區(qū)分,右值的聲明符號(hào)為”&&”。

下面是從其他文章中copy的測(cè)試代碼,詳細(xì)內(nèi)容介紹可以參考對(duì)應(yīng)的reference:

#include "rvalue_references.hpp"
#include <iostream>
#include <string>
#include <utility>//
// reference: http://en.cppreference.com/w/cpp/language/reference
void double_string(std::string& s)
{s += s; // 's' is the same object as main()'s 'str'
}char& char_number(std::string& s, std::size_t n)
{return s.at(n); // string::at() returns a reference to char
}int test_lvalue_references1()
{// 1. Lvalue references can be used to alias an existing object (optionally with different cv-qualification):std::string s = "Ex";std::string& r1 = s;const std::string& r2 = s;r1 += "ample";           // modifies s//  r2 += "!";               // error: cannot modify through reference to conststd::cout << r2 << '\n'; // prints s, which now holds "Example"// 2. They can also be used to implement pass-by-reference semantics in function calls:std::string str = "Test";double_string(str);std::cout << str << '\n';// 3. When a function's return type is lvalue reference, the function call expression becomes an lvalue expressionstd::string str_ = "Test";char_number(str_, 1) = 'a'; // the function call is lvalue, can be assigned tostd::cout << str_ << '\n';return 0;
}//
// reference: http://en.cppreference.com/w/cpp/language/reference
static void f(int& x)
{std::cout << "lvalue reference overload f(" << x << ")\n";
}static void f(const int& x)
{std::cout << "lvalue reference to const overload f(" << x << ")\n";
}static void f(int&& x)
{std::cout << "rvalue reference overload f(" << x << ")\n";
}int test_rvalue_references1()
{// 1. Rvalue references can be used to extend the lifetimes of temporary objects// (note, lvalue references to const can extend the lifetimes of temporary objects too, but they are not modifiable through them):std::string s1 = "Test";//  std::string&& r1 = s1;           // error: can't bind to lvalueconst std::string& r2 = s1 + s1; // okay: lvalue reference to const extends lifetime//  r2 += "Test";                    // error: can't modify through reference to conststd::string&& r3 = s1 + s1;      // okay: rvalue reference extends lifetimer3 += "Test";                    // okay: can modify through reference to non-conststd::cout << r3 << '\n';// 2. More importantly, when a function has both rvalue reference and lvalue reference overloads,// the rvalue reference overload binds to rvalues (including both prvalues and xvalues),// while the lvalue reference overload binds to lvalues:int i = 1;const int ci = 2;f(i);  // calls f(int&)f(ci); // calls f(const int&)f(3);  // calls f(int&&)// would call f(const int&) if f(int&&) overload wasn't providedf(std::move(i)); // calls f(int&&)// This allows move constructors, move assignment operators, and other move-aware functions// (e.g. vector::push_back() to be automatically selected when suitable.return 0;
}/
// reference: http://www.bogotobogo.com/cplusplus/C11/5_C11_Move_Semantics_Rvalue_Reference.php
static void printReference(int& value)
{std::cout << "lvalue: value = " << value << std::endl;
}static void printReference(int&& value)
{std::cout << "rvalue: value = " << value << std::endl;
}static int getValue()
{int temp_ii = 99;return temp_ii;
}int test_rvalue_references2()
{int ii = 11;printReference(ii);printReference(getValue());  //  printReference(99);return 0;
}// references: https://msdn.microsoft.com/en-us/library/dd293668.aspx
template<typename T> struct S;// The following structures specialize S by 
// lvalue reference (T&), const lvalue reference (const T&), 
// rvalue reference (T&&), and const rvalue reference (const T&&).
// Each structure provides a print method that prints the type of 
// the structure and its parameter.
template<typename T> struct S<T&> {static void print(T& t){std::cout << "print<T&>: " << t << std::endl;}
};template<typename T> struct S<const T&> {static void print(const T& t){std::cout << "print<const T&>: " << t << std::endl;}
};template<typename T> struct S<T&&> {static void print(T&& t){std::cout << "print<T&&>: " << t << std::endl;}
};template<typename T> struct S<const T&&> {static void print(const T&& t){std::cout << "print<const T&&>: " << t << std::endl;}
};// This function forwards its parameter to a specialized
// version of the S type.
template <typename T> void print_type_and_value(T&& t)
{S<T&&>::print(std::forward<T>(t));
}// This function returns the constant string "fourth".
const std::string fourth() { return std::string("fourth"); }int test_rvalue_references3()
{// The following call resolves to:// print_type_and_value<string&>(string& && t)// Which collapses to:// print_type_and_value<string&>(string& t)std::string s1("first");print_type_and_value(s1);// The following call resolves to:// print_type_and_value<const string&>(const string& && t)// Which collapses to:// print_type_and_value<const string&>(const string& t)const std::string s2("second");print_type_and_value(s2);// The following call resolves to:// print_type_and_value<string&&>(string&& t)print_type_and_value(std::string("third"));// The following call resolves to:// print_type_and_value<const string&&>(const string&& t)print_type_and_value(fourth());return 0;
}

GitHub: https://github.com/fengbingchun/Messy_Test

總結(jié)

以上是生活随笔為你收集整理的C++11中rvalue references的使用的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

歡迎分享!

轉(zhuǎn)載請(qǐng)說(shuō)明來(lái)源于"生活随笔",并保留原作者的名字。

本文地址:C++11中rvalue references的使用