移动语义 Move Semantics
为了减少拷贝构造函数在堆上重新分配内存的时间,并且构造函数的参数是临时值,
使用右值引用来构造类,此构造函数的实现要把原来的资源指针设置为空nullptr
,delete才不会出错
在Entity初始化列表中,声明了一个类型是右值引用的左值,所以要通过std::move()
强行转化为右值引用,
也可以直接写强制类型转换(String&&)
然后对比测试一下执行时间
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
| #include <iostream> #define ps(str) std::cout << str; class Timer { public: Timer(const char* name) :m_Name(name), m_Stopped(false) { m_StartTimepoint = std::chrono::high_resolution_clock::now(); } ~Timer() { if (!m_Stopped) { Stop(); } } void Stop() { auto endTimePoint = std::chrono::high_resolution_clock::now();
long long start = std::chrono::time_point_cast<std::chrono::microseconds>(m_StartTimepoint).time_since_epoch().count(); long long end = std::chrono::time_point_cast<std::chrono::microseconds>(endTimePoint).time_since_epoch().count(); std::cout << "花费时间: " << (end - start) << " ms\n"; m_Stopped = true; } private: const char* m_Name; std::chrono::time_point<std::chrono::steady_clock> m_StartTimepoint; bool m_Stopped;
}; class String { public: String() = default; String(const char* string) { printf("Created!\n"); m_Size = strlen(string); m_Data = new char[m_Size]; memcpy(m_Data,string,m_Size); }
String(const String& other) { printf("Copied!\n"); m_Size = other.m_Size; m_Data = new char[m_Size]; memcpy(m_Data,other.m_Data,m_Size); }
String(String&& other) noexcept { printf("Moved!\n"); m_Size = other.m_Size; m_Data = other.m_Data;
other.m_Size = 0; other.m_Data = nullptr; }
~String() { ps("Destroyed!\n"); delete m_Data; }
public: void Print() { for (uint32_t i = 0; i < m_Size; i++) { printf("%c",m_Data[i]); } printf("\n"); } private: char* m_Data; uint32_t m_Size; };
class Entity { public: Entity() = default;
Entity(const String& name) :m_Name((name)) {}
Entity(String&& name) :m_Name(std::move(name)) {}
~Entity() = default; void PrintName() { m_Name.Print(); } private: String m_Name; };
int main() {
{
Timer timer("1"); String temp("1234567890\ 1234567890\ 1234567890\ 1234567890"); Entity entity1(temp); }
{ Timer timer("2"); Entity entity("1234567890\ 1234567890\ 1234567890\ 1234567890"); }
std::cin.get(); }
|
只要某个类的成员变量是在堆上分配内存的,那么就可以写接受右值引用的构造函数
移动赋值 Move Assignment
创建新变量时使用=
赋值符号实际上调用的是构造函数,
而对已经存在的变量使用赋值运算符实际上是调用xx& operator =()
函数
重载赋值函数时,因为拿到是RValue的资源,所以我们先要正确的释放自己在堆上的资源
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
| #include "../src/include/local.h" #define ps(str) std::cout << str; class Timer { public: Timer(const char* name) :m_Name(name), m_Stopped(false) { m_StartTimepoint = std::chrono::high_resolution_clock::now(); } ~Timer() { if (!m_Stopped) { Stop(); } } void Stop() { auto endTimePoint = std::chrono::high_resolution_clock::now();
long long start = std::chrono::time_point_cast<std::chrono::microseconds>(m_StartTimepoint).time_since_epoch().count(); long long end = std::chrono::time_point_cast<std::chrono::microseconds>(endTimePoint).time_since_epoch().count(); std::cout << "花费时间: " << (end - start) << " ms\n"; m_Stopped = true; } private: const char* m_Name; std::chrono::time_point<std::chrono::steady_clock> m_StartTimepoint; bool m_Stopped;
}; class String { public: String() = default; String(const char* string) { printf("Created!\n"); m_Size = strlen(string); m_Data = new char[m_Size]; memcpy(m_Data,string,m_Size); }
String(const String& other) { printf("Copied!\n"); m_Size = other.m_Size; m_Data = new char[m_Size]; memcpy(m_Data,other.m_Data,m_Size); }
String(String&& other) noexcept { printf("Moved! Constructor\n"); m_Size = other.m_Size; m_Data = other.m_Data;
other.m_Size = 0; other.m_Data = nullptr; }
String& operator=(const String& other) { delete[] m_Data; m_Size = other.m_Size; m_Data = new char[m_Size]; memcpy(m_Data, other.m_Data, m_Size);
return *this; }
String& operator=(String&& other) noexcept { if (this == &other) { ps("相同\n"); return *this; }
printf("Move assignment\n"); delete[] m_Data; m_Size = other.m_Size; m_Data = other.m_Data;
other.m_Size = 0; other.m_Data = nullptr;
return *this; }
~String() { ps("Destroyed!\n"); delete m_Data; }
public: void Print() { for (uint32_t i = 0; i < m_Size; i++) { printf("%c",m_Data[i]); } printf("\n"); } private: char* m_Data; uint32_t m_Size; };
class Entity { public: Entity() = default;
Entity(const String& name) :m_Name((name)) {}
Entity(String&& name) :m_Name(std::move(name)) {}
~Entity() = default; void PrintName() { m_Name.Print(); } private: String m_Name; };
int main() { String apple = "Apple"; String dest; dest = (String&&)(apple); dest.Print(); apple.Print();
std::cin.get(); }
|
std::array<,>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| template<typename T,size_t N> class Array { public: constexpr int Size() const { return N; } T& operator[](size_t index) { return m_Data[index]; } const T& operator[](size_t index)const { return m_Data[index]; } private: T m_Data[N]; };
int main() { int size = 5; Array<int, 5> data;
const auto& arrayReference = data; for (int i = 0; i < data.Size(); i++) { std::cout << arrayReference[i] << std::endl; }
std::cin.get(); }
|
Iterator
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| #include <unordered_map>
int main() { using ScoreMap = std::unordered_map<std::string, int>; ScoreMap map; map["String"] = 5; map["C++"] = 1; for (ScoreMap::iterator it = map.begin(); it != map.end(); it++) { const auto& key = it->first; const auto& value = it->second;
std::cout << key << ", " << value<< std::endl; }
for (auto kv : map) { auto& key = kv.first; auto& value = kv.second; std::cout << key << ", " << value << std::endl; }
for (auto[key,value] : map) { std::cout << key << ", " << value << std::endl; } std::cin.get(); }
|
制作Iterator
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
| template<typename Vector> class VectorIterator { public: using ValueType = typename Vector::ValueType; using PointerType = ValueType*; using ReferenceType = ValueType&; public: VectorIterator(PointerType ptr) :m_Ptr(ptr) {}
VectorIterator& operator++() { m_Ptr++; return *this; }
VectorIterator operator++(int) { VectorIterator tmp = *this; ++(*this); return tmp; }
VectorIterator& operator--() { m_Ptr--; return *this; }
VectorIterator operator--(int) { VectorIterator tmp = *this; --(*this); return tmp; }
ReferenceType operator[](int index) { return *(m_Ptr + index); }
PointerType operator->() { return m_Ptr; }
ReferenceType operator*() { return *m_Ptr; }
bool operator==(const VectorIterator& other) const { return m_Ptr == other.m_Ptr; }
bool operator!=(const VectorIterator& other) const { return !(*this == other); } private: PointerType m_Ptr; };
template<typename T> class Vector { public: using ValueType = T; using Iterator = VectorIterator<Vector<T>>; public: Vector() { ReAlloc(2); }
~Vector() { delete[] m_Data; }
void PushBack(const T& value) { if (m_Size >= m_Capacity) ReAlloc(m_Capacity + m_Capacity / 2); m_Data[m_Size++] = value; }
void PushBack(T&& value) { if (m_Size >= m_Capacity) ReAlloc(m_Capacity + m_Capacity / 2); m_Data[m_Size] = std::move(value); m_Size++; }
template<typename... Args> T& EmplaceBack(Args&&... args) { if (m_Size >= m_Capacity) ReAlloc(m_Capacity + m_Capacity / 2);
m_Data[m_Size] = T(std::forward<Args>(args)...); return m_Data[m_Size++]; }
void PopBack() { if (m_Size > 0) { m_Size--; m_Data[m_Size].~T(); } }
void Clear() { for (size_t i = 0; i < m_Size; i++) m_Data[i].~T(); m_Size = 0; }
T& operator[](size_t index) { if (index >= m_Size) {
} return m_Data[index]; }
const T& operator[](size_t index) const { if (index >= m_Size) {
} return m_Data[index]; }
size_t Size() const { return m_Size; }
Iterator begin() { return Iterator(m_Data); }
Iterator end() { return Iterator(m_Data + m_Size); } private: void ReAlloc(size_t newCapacity) { T* newBlock = new T[newCapacity];
if (newCapacity < m_Size) m_Size = newCapacity;
for (size_t i = 0; i < m_Size; i++) newBlock[i] = std::move(m_Data[i]);
delete[] m_Data; m_Data = newBlock; m_Capacity = newCapacity; } private: T* m_Data = nullptr;
size_t m_Size = 0; size_t m_Capacity = 0; };
int main() { Vector<int> values; values.EmplaceBack(1); values.EmplaceBack(2); values.EmplaceBack(9); values.EmplaceBack(8); values.EmplaceBack(76); values.EmplaceBack(7);
std::cout << "Not using iterator:\n"; for (size_t i = 0; i < values.Size(); i++) { std::cout << values[i] << std::endl; }
std::cout << "Range-based for loop:\n"; for (int value : values) { std::cout << value << std::endl; } std::cin.get(); }
|