Lauen_1

Stay foolish

2-8. lvalue and rvalue References

左值引用与右值引用

C++左值性的定义: 一个表达式不是左值就是右值,与C完全不一样。

C/C++中的类型系统可以有多种划分方法,例如基本类型与复合类型(也叫派生类型)、标量类型与聚集类型,

还有一种是根据对象模型来分,分为对象类型、不完整类型、函数类型和引用类型(C没有引用类型),

由于C++规定引用类型属于左值,同时也把函数纳入左值范畴,因此C++的左值包括了对象模型划分方法中的所有类型,

再使用类似C那种左值定义方法是多余的,C++仅需要指出一个表达式不是左值就是右值就行了,但C就不行,因为C

存在既不是左值也不是右值的表达式:函数指示符。所以引申出左值引用和右值引用

& (lvalue) and && (rvalue),这两个引用引用的目的是取代copying objects,用于move semantics。

an rvalue reference should be used to move construct or move assign objects in place of copy operations where appropriate.

Move semantics should not be used to replace passing parameters to methods by const reference.

A move operation could be faster than a copy, in the worst case it can be slower than a copy and it will always be slower than passing by const reference.

在进行copy操作时,使用move操作进行取代。一般来说不用使用move操作替换const引用,

move操作一般比copy快,极端情况下可能比copy慢,但是肯定比const reference慢。

 1.A Class that Counts the Number of Instances

#include <iostream>

using namespace std;

class MyClass
{
private:
    static int s_Counter;

    int* m_Member{ &s_Counter };

public:
    MyClass()
    {
        ++(*m_Member);
    }

    ~MyClass()
    {
        --(*m_Member);
        m_Member = nullptr;
    }

    int GetValue() const
    {
        return *m_Member;
    }
};

int MyClass::s_Counter{ 0 };

int main()
{
    auto object1 = MyClass();
    cout << object1.GetValue() << endl;

    {
        auto object2 = MyClass();
        cout << object2.GetValue() << endl;
    }

    auto object3 = MyClass();
    cout << object3.GetValue() << endl;

    return 0;
}
View Code

2. Copying MyClass

 1 #include <iostream>
 2 
 3 using namespace std;
 4 
 5 class MyClass
 6 {
 7 private:
 8     static int s_Counter;
 9 
10     int* m_Member{ &s_Counter };
11 
12 public:
13     MyClass()
14     {
15         ++(*m_Member);
16         cout << "Constructing: " << GetValue() << endl;
17     }
18 
19     ~MyClass()
20     {
21         --(*m_Member);
22         m_Member = nullptr;
23 
24         cout << "Destructing: " << s_Counter << endl;
25     }
26 
27     MyClass(const MyClass& rhs)
28         : m_Member{ rhs.m_Member }
29     {
30         ++(*m_Member);
31         cout << "Copying: " << GetValue() << endl;
32     }
33 
34     int GetValue() const
35     {
36         return *m_Member;
37     }
38 };
39 
40 int MyClass::s_Counter{ 0 };
41 
42 MyClass CopyMyClass(MyClass parameter)
43 {
44     return parameter;
45 }
46 
47 int main()
48 {
49     auto object1 = MyClass();
50 
51     {
52         auto object2 = MyClass();
53     }
54 
55     auto object3 = MyClass();
56     auto object4 = CopyMyClass(object3);
57 
58     return 0;
59 }
View Code

Move constructors can be utilized to cut down on the complexity of a copy constructor.

A rvalue reference is a guarantee from the compiler that the object referenced by the variable was a temporary object.

This means that you are free to cannibalize the object so that you can implement a copy operation faster than if the

pre-existing state was needed to bepreserved. 

move操作降低了copy constructor的复杂度,右值引用就是让编译器确认零时变量能够进行拷贝

3. Adding a Move Constructor to MyClass

 1 #include <iostream>
 2 
 3 using namespace std;
 4 
 5 class MyClass
 6 {
 7 private:
 8     static int s_Counter;
 9     int* m_Member{ &s_Counter };
10 
11 public:
12     MyClass()
13     {
14         ++(*m_Member);
15         cout << "Constructing: " << GetValue() << endl;
16     }
17 
18     ~MyClass()
19     {
20         if (m_Member)
21         {
22             --(*m_Member);
23             m_Member = nullptr;
24             cout << "Destructing: " << s_Counter << endl;
25         }
26         else
27         {
28             cout << "Destroying a moved-from instance" << endl;
29         }
30     }
31 
32     MyClass(const MyClass& rhs)
33         : m_Member{ rhs.m_Member }
34     {
35         ++(*m_Member);
36         cout << "Copying: " << GetValue() << endl;
37     }
38 
39     MyClass(MyClass&& rhs)
40         : m_Member{ rhs.m_Member }
41     {
42         cout << hex << showbase;
43         cout << "Moving: " << &rhs << " to " << this << endl;
44         cout << noshowbase << dec;
45         rhs.m_Member = nullptr;
46     }
47     int GetValue() const
48     {
49         return *m_Member;
50     }
51 };
52 
53 int MyClass::s_Counter{ 0 };
54 
55 MyClass CopyMyClass(MyClass parameter)
56 {
57     return parameter;
58 }
59 
60 int main()
61 {
62     auto object1 = MyClass();
63 
64     {
65         auto object2 = MyClass();
66     }
67 
68     auto object3 = MyClass();
69     auto object4 = CopyMyClass(object3);
70 
71     return 0;
72 }
View Code

4.Comparing Copy Constructors with Move Constructors

 1 #include <chrono>
 2 #include <iostream>
 3 #include <string>
 4 #include <vector>
 5 
 6 using namespace std;
 7 using namespace chrono;
 8 using namespace literals;
 9 
10 class MyClass
11 {
12 private:
13     vector<string> m_String{
14         "This is a pretty long string that"
15         " must be copy constructed into"
16         " copyConstructed!"s
17     };
18 
19     int m_Value{ 1 };
20 
21 public:
22     MyClass() = default;
23     MyClass(const MyClass& rhs) = default;
24     MyClass(MyClass&& rhs) = default;
25 
26     int GetValue() const
27     {
28         return m_Value;
29     }
30 };
31 
32 int main()
33 {
34     using MyVector = vector<MyClass>;
35     constexpr unsigned int ITERATIONS{ 1000000U };
36 
37     MyVector copyConstructed(ITERATIONS);
38     int value{ 0 };
39 
40     auto copyStartTime = high_resolution_clock::now();
41     for (unsigned int i=0; i < ITERATIONS; ++i)
42     {
43         MyClass myClass;
44         copyConstructed.push_back(myClass);
45         value = myClass.GetValue();
46     }
47     auto copyEndTime = high_resolution_clock::now();
48 
49     MyVector moveConstructed(ITERATIONS);
50 
51     auto moveStartTime = high_resolution_clock::now();
52     for (unsigned int i=0; i < ITERATIONS; ++i)
53     {
54         MyClass myClass;
55         moveConstructed.push_back(move(myClass));
56         value = myClass.GetValue();
57     }
58     auto moveEndTime = high_resolution_clock::now();
59 
60     cout << value << endl;
61 
62     auto copyDuration = duration_cast<milliseconds>(copyEndTime - copyStartTime);
63     cout << "Copy lasted: " << copyDuration.count() << "ms" << endl;
64 
65     auto moveDuration =
66         duration_cast<milliseconds>(moveEndTime - moveStartTime);
67     cout << "Move lasted: " << moveDuration.count() << "ms" << endl;
68 
69     return 0;
70 }
View Code

 

posted on 2016-11-08 12:12  Lauen_1  阅读(140)  评论(0)    收藏  举报

导航