右值引用簡介(中英文對照)
[譯註:本文介紹的“右值引用”是C++11的新特性]
A Brief Introduction to Rvalue References
by Howard E. Hinnant, Bjarne Stroustrup, and Bronek Kozicki
March 10, 2008
右值引用簡介
Howard E. Hinnant、Bjarne Stroustrup和Bronek Kozicki
2008年3月10日
Summary
摘要
Rvalue references is a small technical extension to the C++ language. Rvalue references allow programmers to avoid logically unnecessary copying and to provide perfect forwarding functions. They are primarily meant to aid in the design of higher performance and more robust libraries.
右值引用是C++語言的一處微小的技術擴充套件。右值引用使程式設計師可以避免邏輯上不必要的拷貝並提供完美的轉發函式。其主要目的是協助更高效能和更加健壯的庫的設計。
Introduction
引言
This document gives a quick tour of the new C++ language feature rvalue reference. It is a brief tutorial, rather than a complete reference. For details, see these references.
本文簡潔明快地介紹了C++語言的新特性:右值引用。這只是一份簡短的教程,而非完整的參考。更多細節可以看看參考文獻。
The rvalue reference
右值引用
An rvalue reference is a compound type very similar to C++'s traditional reference. To better distinguish these two types, we refer to a traditional C++ reference as anlvalue reference. When the term reference is used, it refers to both kinds of reference: lvalue reference and rvalue reference.
右值引用是一種複合型別,跟C++的傳統引用很類似。為更準確地區分兩種型別,我們把傳統的C++引用稱為左值引用。而使用“引用”這一術語時,我們的意思同時包含兩種引用:左值引用和右值引用。
An lvalue reference is formed by placing an & after some type.
左值引用通過在型別之後加一個“&”來定義:
A a; A& a_ref1 = a; // an lvalue reference
An rvalue reference is formed by placing an && after some type.
右值引用則在某個型別之後新增兩個“&”:
A a;
A&& a_ref2 = a; // an rvalue reference
An rvalue reference behaves just like an lvalue reference except that it can bind to a temporary (an rvalue), whereas you can not bind a (non const) lvalue reference to an rvalue.
右值引用的行為跟左值引用類似,不同之處在於:右值引用可以繫結到臨時量(右值),而(非const的)左值引用卻不能繫結到右值。
A& a_ref3 = A(); // Error!
A&& a_ref4 = A(); // Ok
Question: Why on Earth would we want to do this?!
問題:究竟為何要使用右值引用?!
It turns out that the combination of rvalue references and lvalue references is just what is needed to easily codemove semantics. The rvalue reference can also be used to achieve perfect forwarding, a heretofore unsolved problem in C++. From a casual programmer's perspective, what we get from rvalue references is more general and better performing libraries.
事實證明,右值引用和左值引用結合起來恰能方便地實現轉移語義。右值引用還可以用於實現完美轉發,這是C++裡面到現在都沒有解決的一個問題。從一般程式設計師的角度來看,使用右值引用,我們得到的將是更加通用,效能也更高的庫。
Move Semantics
Eliminating spurious copies
轉移語義
消除假拷貝
Copying can be expensive. For example, for std::vectors, v2=v1 typically involves a function call, a memory allocation, and a loop. This is of course acceptable where we actually need two copies of a vector, but in many cases, we don't: We often copy a vector from one place to another, just to proceed to overwrite the old copy. Consider:
拷貝的開銷可以很大。舉例來說,對於std::vector,像v2=v1這樣的賦值通常包含一次函式呼叫,一次記憶體分配和一個迴圈。當我們確實需要一個vector的兩份拷貝時,這當然是可接受的,然而很多情況下我們並不需要:我們常常將一個vector從一個地方複製到另一個地方,接著便覆寫了舊的版本。考慮下面的程式碼:
template <class T> swap(T& a, T& b)
{
T tmp(a); // now we have two copies of a
a = b; // now we have two copies of b
b = tmp; // now we have two copies of tmp (aka a)
}
But, we didn't want to have any copies of a or b, we just wanted to swap them. Let's try again:
但我們並不想擁有a或b的任何拷貝,而只是想交換他們。再試試其它辦法:
template <class T> swap(T& a, T& b)
{
T tmp(std::move(a));
a = std::move(b);
b = std::move(tmp);
}
This move() gives its target the value of its argument, but is not obliged to preserve the value of its source. So, for a vector, move() could reasonably be expected to leave its argument as a zero-capacity vector to avoid having to copy all the elements. In other words, move is a potentially destructive read.
move()將其引數的值交給目標變數,但並不保證維持源變數的值。因此對vector來說,我們完全可以期待move()會使其引數成為容量為0的vector,從而避免複製所有元素。換言之,move有可能是破壞性的讀取。
In this particular case, we could have optimized swap by a specialization. However, we can't specialize every function that copies a large object just before it deletes or overwrites it. That would be unmanageable.
在這個特定的例子中,我們也可以使用特化來優化swap。然而,我們無法特化每一個拷貝一個大物件,然後將其刪除或覆寫的函式。那是做不到的。
The first task of rvalue references is to allow us to implement move() without verbosity, or runtime overhead.
右值引用的第一項任務就是允許我們實現move()而無須使用冗長的程式碼或引入執行時開銷。
move
move
The move function really does very little work. All move does is accept either an lvalue or rvalue argument, and return it as an rvaluewithout triggering a copy construction:
move函式完成的工作實際上微乎其微。它所做的就是接受一個左值或右值引數,然後將它作為右值返回而不引發拷貝構造:
template <class T>
typename remove_reference<T>::type&&
move(T&& a)
{
return a;
}
It is now up to client code to overload key functions on whether their argument is an lvalue or rvalue (e.g. copy constructor and assignment operator). When the argument is an lvalue, the argument must be copied from. When it is an rvalue, it can safely be moved from.
然後,由客戶端程式碼負責根據引數是左值或右值的不同情形來過載關鍵函式(如拷貝建構函式和拷貝賦值運算子)。引數是左值時必須拷貝它,是右值時則可以安全地轉移它。
Overloading on lvalue / rvalue
針對左值/右值的過載
Consider a simple handle class that owns a resource and also provides copy semantics (copy constructor and assignment). For example a clone_ptr might own a pointer, and call clone() on it for copying purposes:
考慮一個簡單的持有某種資源同時提供拷貝語義(拷貝建構函式和賦值運算子)的控制代碼類。比如,一個clone_ptr可以擁有一個指標,並基於指標呼叫clone()來達到拷貝物件的目的。
template <class T>
class clone_ptr
{
private:
T* ptr;
public:
// construction
explicit clone_ptr(T* p = 0) : ptr(p) {}
// destruction
~clone_ptr() {delete ptr;}
// copy semantics
clone_ptr(const clone_ptr& p)
: ptr(p.ptr ? p.ptr->clone() : 0) {}
clone_ptr& operator=(const clone_ptr& p)
{
if (this != &p)
{
delete ptr;
ptr = p.ptr ? p.ptr->clone() : 0;
}
return *this;
}
// move semantics
clone_ptr(clone_ptr&& p)
: ptr(p.ptr) {p.ptr = 0;}
clone_ptr& operator=(clone_ptr&& p)
{
std::swap(ptr, p.ptr);
return *this;
}
// Other operations
T& operator*() const {return *ptr;}
// ...
};
Except for the highlighted move semantics section above, clone_ptr is code that you might find in today's books on C++. Clients of clone_ptr might use it like so:
上面的clone_ptr程式碼中,除了特別指明的用於轉移語義的部分之外,其它都是可以在今天的各種C++書上找到的程式碼。clone_ptr的客戶可以這樣使用它:
clone_ptr p1(new derived);
// ...
clone_ptr p2 = p1; // p2 and p1 each own their own pointer
Note that copy constructing or assigning a clone_ptr is a relatively expensive operation. However when the source of the copy is known to be an rvalue, one can avoid the potentially expensive clone() operation by pilfering the rvalue's pointer (no one will notice!). The move constructor above does exactly that, leaving the rvalue in a default constructed state. Themove assignment operator simply swaps state with the rvalue.
注意,clone_ptr的拷貝構造和賦值是開銷較大的操作。然而,如果確知拷貝源是右值,我們可以直接偷走那個右值的指什(沒有人會注意到),從而避免潛在的大開銷clone()操作。上面的轉移建構函式就是這麼做的,把被拷貝的右值置成了預設構造的狀態。轉移賦值運算子則直接跟右值交換了狀態。
Now when code tries to copy an rvalue clone_ptr, or if that code explicitly gives permission to consider the source of the copy an rvalue (using std::move), the operation will execute much faster.
現在,當代碼嘗試拷貝一個clone_ptr右值,或者顯式地允許將拷貝源看作右值(通過std::move),操作執行起來會快很多。
clone_ptr p1(new derived);
// ...
clone_ptr p2 = std::move(p1); // p2 now owns the pointer instead of p1
For classes made up of other classes (via either containment or inheritance), the move constructor and move assignment can easily be coded using the std::move function:
對於由其它類構成的類(通過包含或繼承)來說,使用std::move函式,其轉移建構函式和轉移賦值編寫起來都很容易。
class Derived
: public Base
{
std::vector<int> vec;
std::string name;
// ...
public:
// ...
// move semantics
Derived(Derived&& x) // rvalues bind here
: Base(std::move(x)),
vec(std::move(x.vec)),
name(std::move(x.name)) { }
Derived& operator=(Derived&& x) // rvalues bind here
{
Base::operator=(std::move(x));
vec = std::move(x.vec);
name = std::move(x.name);
return *this;
}
// ...
};
Each subobject will now be treated as an rvalue when binding to the subobject's constructors and assignment operators. std::vector and std::string have move operations coded (just like our eariler clone_ptr example) which will completely avoid the tremendously more expensive copy operations.
現在,繫結到子物件的建構函式或賦值運算子時,每個子物件都被作為右值看待。std::vector和std::string已經實現了轉移操作(就像之前的clone_ptr),從而完全避免了開銷高出數倍的拷貝操作。
Note above that the argument x is treated as an lvalue internal to the move functions, even though it is declared as an rvalue reference parameter. That's why it is necessary to say move(x) instead of just x when passing down to the base class. This is a key safety feature of move semantics designed to prevent accidently moving twice from some named variable. All moves occur only from rvalues, or with an explicit cast to rvalue such as using std::move. If you have a name for the variable, it is an lvalue.
注意,上面的x雖然宣告為右值引用引數,但轉移函式內部卻把它看成左值。這就是為什麼在將它進一步傳給基類的時候我們使用了move(x)而不直接使用x。這是轉移語義的一項重要的安全特性,其目的是避免對命名變數做意外的重複拷貝。所有的轉移要麼發生在右值上,要麼應顯式地轉換成右值,比如使用std::move。命名的變數都是左值。
Question: What about types that don't own resources? (E.g. std::complex?)
問題:不佔資源的型別又是什麼情況呢?(比如std::complex?)
No work needs to be done in that case. The copy constructor is already optimal when copying from rvalues.
那種情況下不需要做任何事,拷貝建構函式在拷貝賦值時已經是最優的了。
Movable but Non-Copyable Types
可轉移但不可拷貝的型別
Some types are not amenable to copy semantics but can still be made movable. For example:
· fstream
· unique_ptr (non-shared, non-copyable ownership)
· A type representing a thread of execution
By making such types movable (though still non-copyable) their utility is tremendously increased. Movable but non-copyable types can be returned by value from factory functions:
有些型別不適用拷貝語義,但仍然是可轉移的。比如:
· fstream
· unique_ptr(非共享、不可拷貝的所有權)
· 代表執行緒的型別
讓這樣的型別變得可轉移(雖仍不能拷貝)可大大提高其效用。可轉移但不可拷貝的型別可從工廠方法中按值返回:
ifstream find_and_open_data_file(/* ... */);
...
ifstream data_file = find_and_open_data_file(/* ... */); // No copies!
In the above example, the underlying file handle is passed from object to object, as long as the source ifstream is an rvalue. At all times, there is still only one underlying file handle, and only one ifstream owns it at a time.
上面的例子中,只要源ifstream是右值,底層的檔案控制代碼就會從一個物件傳到另一個物件。任何時候底層的檔案控制代碼仍然只有一個,且每一時刻只有一個ifstream物件擁有它。
Movable but non-copyable types can also safely be put into standard containers. If the container needs to "copy" an element internally (e.g. vector reallocation) it will move the element instead of copying it.
可轉移但不可拷貝的型別也可以安全地放進標準容器中。如果容器內部需要“拷貝”一個元素(比如vector重新分配記憶體),它會轉移元素而不會拷貝元素。
vector<unique_ptr<base>> v1, v2;
v1.push_back(unique_ptr(new derived())); // ok, moving, not copying
...
v2 = v1; // Compile time error. This is not a copyable type.
v2 = move(v1); // Move ok. Ownership of pointers transferred to v2.
Many standard algorithms benefit from moving elements of the sequence as opposed to copying them. This not only provides better performance (like the improved std::swap implementation described above), but also allows these algorithms to operate on movable but non-copyable types. For example the following code sorts a vector<unique_ptr<T>> based on comparing the pointed-to types:
序列中的元素可以轉移而無需拷貝,這可使許多標準演算法受益。這不僅帶來了更高的效能(就像之前描述的更好的std::swap實現),還讓這些演算法能夠操作可轉移但不可拷貝的型別。比如,下面的程式碼基於被指向的型別來給一個vector<unique_ptr<T>>排序:[譯註:根據C++11新標準,巢狀模板引數無須再在兩個“>”之間加上一個空格。]
struct indirect_less
{
template <class T>
bool operator()(const T& x, const T& y)
{return *x < *y;}
};
...
std::vector<std::unique_ptr<A>> v;
...
std::sort(v.begin(), v.end(), indirect_less());
As sort moves the unique_ptr's around, it will use swap (which no longer requires Copyability) or move construction / move assignment. Thus during the entire algorithm, the invariant that each item is owned and referenced by one and only one smart pointer is maintained. If the algorithm were to attempt a copy (say, by programming mistake) a compile time error would result.
當sort四處移動unique_ptr時,它將使用swap(swap不再要求被交換的物件“可拷貝”)或轉移構造/轉移賦值。於是,在整個演算法中,“每個專案被一個且僅有一個智慧指標擁有並引用”的不變式得以維持。演算法如果試圖拷貝專案(比如出於程式錯誤)將引發編譯錯誤。
Perfect Forwarding
完美轉發
Consider writing a generic factory function that returns a std::shared_ptr for a newly constructed generic type. Factory functions such as this are valuable for encapsulating and localizing the allocation of resources. Obviously, the factory function must accept exactly the same sets of arguments as the constructors of the type of objects constructed. Today this might be coded as:
考慮編寫一個通用的工廠函式,它基於新建立的一般型別的物件返回std::shared_ptr。這樣的工廠函式對於資源分配的封裝和區域性化意義非淺。顯而易見的是:新建立物件的建構函式能接受什麼引數,工廠函式也必須能接受同樣的一組引數:
template <class T>
std::shared_ptr<T>
factory() // no argument version
{
return std::shared_ptr<T>(new T);
}
template <class T, class A1>
std::shared_ptr<T>
factory(const A1& a1) // one argument version
{
return std::shared_ptr<T>(new T(a1));
}
// all the other versions
In the interest of brevity, we will focus on just the one-parameter version. For example:
為簡短起見,我們關注僅有一個引數的版本。比如:
std::shared_ptr<A> p = factory<A>(5);
Question: What if T's constructor takes a parameter by non-const reference?
問題:如果T的建構函式接受一個非const引用引數又當如何?
In that case, we get a compile-time error as the const-qualifed argument of the factory function will not bind to the non-const parameter of T's constructor.
那種情況下我們將得到一條編譯錯誤:工廠函式中const修飾的實參不能繫結到T建構函式中的非const形參。
To solve that problem, we could use non-const parameters in our factory functions:
為解決這一問題,我們在工廠函式中使用非const引數。
template <class T, class A1>
std::shared_ptr<T>
factory(A1& a1)
{
return std::shared_ptr<T>(new T(a1));
}
This is much better. If a const-qualified type is passed to the factory, the const will be deduced into the template parameter (A1 for example) and then properly forwarded to T's constructor. Similarly, if a non-const argument is given to factory, it will be correctly forwarded to T's constructor as a non-const. Indeed, this is precisely how forwarding applications are coded today (e.g. std::bind).
這樣就好多了。如果const修飾的型別傳入factory,const將被推導到模板形參上(比如A1),然後合情合理地轉發到T的建構函式上。類似地,如果非const實參傳入factory,它將作為非const量正確轉發到T的構造數上。實際上,這恰恰是今天的轉發應用(比如std::bind)所採用的實現方式。
However, consider:
然而,考慮下面的情況:
std::shared_ptr<A> p = factory<A>(5); // error
A* q = new A(5); // ok
This example worked with our first version of factory, but now it's broken: The "5" causes the factory template argument to be deduced as int& and subsequently will not bind to the rvalue "5". Neither solution so far is right. Each breaks reasonable and common code.
這個例子在我們第一版的factory中沒有問題,現在卻不行了。“5”將factory的模板引數推導為int&,接下來int&卻不能繫結到右值“5”。到目前,兩種方案都不正確。每一種都會打破一些合理的、常見的程式碼。
Question: What about overloading on every combination of AI& and const AI&?
問題:針對每一種AI&和const AI&的組合進行過載行不行?
This would allow us to handle all examples, but at a cost of an exponential explosion: For our two-parameter case, this would require 4 overloads. For a three-parameter factory we would need 8 additional overloads. For a four-parameter factory we would need 16, and so on. This is not a scalable solution.
這樣我們可以應付所有示例程式碼,代價卻是指數級的爆炸:雙引數的情況需要4種過載。三引數的factory需要8種過載。四引數的factory需要16種。依此類推。這不是一個可伸縮的解決方案。
Rvalue references offer a simple, scalable solution to this problem:
右值引用為該問題提供了一個簡易的、可伸縮的解決方案:
template <class T, class A1>
std::shared_ptr<T>
factory(A1&& a1)
{
return std::shared_ptr<T>(new T(std::forward<A1>(a1)));
}
Now rvalue arguments can bind to the factory parameters. If the argument is const, that fact gets deduced into the factory template parameter type.
現在右值實參可以繫結到factory的形參了。如果實參帶有const,這一事實將被推導到factory的模板引數型別上。
Question: What is that forward function in our solution?
問題:我們的解決方案中,那個forward是做什麼的?
Like move, forward is a simple standard library function used to express our intent directly and explicitly, rather than through potentially cryptic uses of references. We want to forward the argument a1, so we simply say so.
類似move,forward也是一個簡單的庫函式,也是用於直接、顯式地表達意圖,而不必通過可能非常神祕的引用語法。我們想要轉發實參a1,於是便直接這麼寫。
Here, forward preserves the lvalue/rvalue-ness of the argument that was passed to factory. If an rvalue is passed to factory, then an rvalue will be passed to T's constructor with the help of the forward function. Similarly, if an lvalue is passed to factory, it is forwarded to T's constructor as an lvalue.
在這裡,forward保持了factory實參的左值/右值屬性。如果右值傳入factory,那麼在forward函式的幫助下,傳入T建構函式的也是右值。同樣,如果左值傳入factory,那它也將作為左值轉發給T的建構函式。
The definition of forward looks like this:
forward可以這樣定義:
template <class T>
struct identity
{
typedef T type;
};
template <class T>
T&& forward(typename identity<T>::type&& a)
{
return a;
}
[譯註:後續的“參考文獻”,“分享您的觀點”和“作者簡介”未翻譯]
References
As one of the main goals of this paper is brevity, there are details missing from the above description. But the above content represents 95% of the knowledge with a fraction of the reading.
This proposal was initially put forth in the following paper. The present article is substantially a reprint of the original proposal:
Hinnant, Howard, E., Bjarne Stroustrap, and Bronek Kozicki. A Brief Introduction to Rvalue References
For further details on the motivation of move semantics, such as performance tests, details of movable but non-copyable types, and many other details please seeN1377.
For a very thorough treatment of the forwarding problem, please see N1385.
For further applications of the rvalue reference (besides move semantics and perfect forwarding), please seeN1690.
For proposed wording for the language changes required to standardize the rvalue reference, please seeN1952.
For a summary of the impact the rvalue reference will have on the standard library, please seeN1771.
For proposed wording for the library changes required to take advantage of the rvalue reference, please see:
·
N1856
·
N1857
·
N1858
·
N1859
·
N1860
·
N1861
·
N1862
For a proposal to extend the rvalue reference to the implicit object parameter (this), please seeN1821.
Share your opinion
Have an opinion about Rvalue references?
About the Authors
Howard Hinnant is the lead author of the rvalue reference proposals for the next C++ standard. He implemented and maintained the standard C++ library for Metrowerks/Motorola/Freescale from the late 90's to 2005. He is currently a senior software engineer at Apple and serving on the C++ standards committee as Library Working Group chairman.
Bjarne Stroustrup is the designer and original implementor of the C++ Programming Language. He is currently the College of Engineering Endowed Chair in Computer Science at Texas A&M University. He formerly worked as the head of AT&T Lab's Large-scale Programming Research department, from its creation until late 2002.
Bronek Kozicki is an experienced C++ programmer. He is a member of BSI C++ panel and author of "extending move semantics to *this" proposal (N1821, evolved to N2439). Bronek currently works for a leading investment bank in London.
相關推薦
右值引用簡介(中英文對照)
[譯註:本文介紹的“右值引用”是C++11的新特性] A Brief Introduction to Rvalue References by Howard E. Hinnant, Bjarne Stroustrup, and Bronek Kozicki March 1
計算機常用英語大全 (中英文對照)
調用 hash scom selection optional miss 域名服務器 password ip數據報 CPU(Center Processor Unit)中央處理單元 mainboard主板 RAM(random access memory
收藏 | 雲端計算領域最全常用術語(中英文對照),你知道多少個?
“雲”發展得如此火熱,“雲”術語層出不窮。為了緊跟上科技潮流,做雲端計算領域的知識達人,小編整理了45個雲端計算領域常用的術語(含中英文對照)及其解釋,以供愛學習的你們參考,一起讓科技知識儲備量上升一個level~ 本文內容主要包含: •關於虛擬化 •關於雲端計算技術 •關於雲
C++11右值引用簡介
C++11右值引用 最近做的某個專案,由於與國外的某些東西有關。接觸到很多C++11、C++14的語法。一方面不時驚歎居然能這麼寫,另一方面覺得國外的技術確實比國內的發達,至少很多國內覺得新的技術,國
計算機常用英語大全 (中英文對照)
CPU(Center Processor Unit)中央處理單元 mainboard主機板 RAM(random access memory)隨機儲存器(記憶體) ROM(Read Only Memory)只讀儲存器 Floppy Disk軟盤 Hard Dis
彙編指令的英文全稱(中英文對照)
資料傳輸指令 ───────────────────────────────────────它們在存貯器和暫存器、暫存器和輸入輸出埠之間傳送資料. 1. 通用資料傳送指令. MOV 傳送字或位元組. MOVSX 先符號擴充套件,再傳送. MOVZX 先零擴充套件,再傳送. PUSH 把字壓入堆疊. POP 把
第15課 右值引用(2)_std::move和移動語義
可見 div 強制轉換 let 技術分享 移動語義 ptr align 講解 1. std::move (1)std::move的原型 template<typename T> typename remove_reference<T>::type&
C++11 右值引用(1)
先參考上一節 C++11 左值 右值 ,本節是右值引用的基礎及判斷方法。 一 右值引用 C++11新增的右值引用概念,用&&表示。 二 引用型別 引用型別 可以引用的值類別 備註
C++ 引用& 和 右值引用&& (1)
我們先來簡單介紹下&引用: C和C++使用&符號來只是變數的地址。C++給&符號賦予了另一個含義,將其來宣告引用。 例如,要將rodents作為rats變數的別名,可以這樣做: int rats; int & rodents = rates;
C++11 右值引用(4)std::forward
一 例子 先看一段程式碼,然後分析。 #include <iostream> void out(int& t) { cout << "out T&" << endl; } void out(int&&
C++ 引用& 和 右值引用&& (1)
我們先來簡單介紹下&引用: C和C++使用&符號來只是變數的地址。C++給&符號賦予了另一個含義,將其來宣告引用。 例如,要將rodents作為rats變數的別名,可以這樣做: int rats; int & rodents = rat
C++11標準之右值引用(ravalue reference)(轉載)
臨時物件的產生和拷貝所帶來的效率折損,一直是C++所為人詬病的問題。但是C++標準允許編譯器對於臨時物件的產生具有完全的自由度,從而發展出了Copy Elision、RVO(包括NRVO)等編譯器優化技術,它們可以防止某些情況下臨時物件產生和拷貝。下面簡單地介紹一下Copy Elision、RVO
C++的雜七雜八:我家的返回值才不可能這麼傲嬌(右值引用和移動語義)
大凡程式語言,都會有“函式”這個概念。而對於外部而言,一個函式最重要的部分就是它的返回值了。 說這裡,返回值其實應該是一個很簡單的話題。當需要通過函式傳遞一個值出去的時候,使用返回值不是理所當然的嘛,比如說,像下面這樣: int add(int a, int b)
左值和右值、左值引用與右值引用(2)
表示式可以分為以下值類別之一: 左值Lvalue:如果表示式不是const限定的,則表示式可以出現在賦值表示式的左側。 x值:要過期的右值引用。 右值(Prvalue) rvalue:非xvalue表示式,僅出現在賦值表示式的右側。Rvalues包括xvalues和
C++11的右值引用(一)——左值(lvalue),純右值(prvalue)和將亡值(xvalue)
基本概念 C++11之前只有左值和右值的概念:lvalue,rvalue。左值可以取地址,右值不能取地址。 但是C++11之後又劃分的更加詳細了,分為左值(lvalue),純右值(prvalue)還有將亡值(xvalue),關係如下: 之前是lva
圖說函式模板右值引用引數(T&&)型別推導規則(C++11)
見下圖: 規律總結: 只要我們傳遞一個基本型別是A④的左值,那麼,傳遞後,T的型別就是A&,形參在函式體中的型別就是A&。 只要我們傳遞一個基本型別是A的右值,那麼,傳遞後,T的型別就是A,形參在函式體中的型別就是A&&。 另外,模板引數型別推導是保留cv限定符(cv-
深入淺出C++11(3) -- 右值引用和move語義
右值引用 什麼是lvalue, 什麼是rvalue? lvalue: 具有儲存性質的物件,即lvalue物件,是指要實際佔用記憶體空間、有記憶體地址的那些實體物件,例如:變數(variables)、函式、函式指標等。 rvalue:相比較於lvalue就是所謂的沒有儲存性質
C++11 的右值引用(Rvalue reference)——細微卻最重要的改動
@王潛升 提到棧區物件的問題,只是右值引用解決的問題之一。更全面一些的話,可以說右值引用解決的是各種情形下物件的資源所有權轉移的問題。第一次碼長文,程式碼都是臨時手敲,如有錯誤歡迎拍磚。=====C++11之前,移動語義的缺失是C++最令人詬病的問題之一。舉個栗子:問題一:如何將大象放入冰箱?這個答案是眾所周
C++引用(左值引用,右值引用)
特點: 引用:引用本質指標實現。 引用一旦初始化, 不會引用其他變數。 右值引用目的:快速建立暫存器資料的引用,就是還沒有記憶體實體的資料可以立即建立一個引用。 (一般寫模板函式有一個左值引用的模板函式,都會對應一個右值引用的模板函式,即使實現程式碼是相同的。
看完這個你還不理解右值引用和移動構造 你就可以來咬我(上)
C++ 右值引用 & 新特性 C++ 11中引入的一個非常重要的概念就是右值引用。理解右值引用是學習“移動語義”(move