c++基础知识回顾

C++基础知识回顾

  • 左右引用

左值:有名字、可取地址、可多次使用的对象(int x; x)。

右值:临时对象或将亡值,通常不能取稳定地址(如 3, x+1, std::string("hi") 返回值等)。

    • T&左值引用,只能绑定到左值。
    • const T&:可绑定到左值右值(延长临时寿命)。
    • T&&右值引用,只能绑定到右值(将亡值)。
    • auto&&(函数模板形参)若配合类型推导,称转发引用/万能引用,能“随被实参的值类别”变化。

其中例如下面代码:

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
#include <iostream>
#include <string>
#include <utility>
struct Big {
std::string s;
Big() { std::cout << "Big()\n"; }
Big(std::string t) : s(std::move(t)) { std::cout << "Big(string)\n"; }

Big(const Big& b) : s(b.s) { std::cout << "Big(const Big&) [copy]\n"; }
Big(Big&& b) noexcept : s(std::move(b.s)) { std::cout << "Big(Big&&) [move]\n"; }

Big& operator=(const Big& b) {
std::cout << "operator=(const Big&) [copy assign]\n";
s = b.s; return *this;
}
Big& operator=(Big&& b) noexcept {
std::cout << "operator=(Big&&) [move assign]\n";
s = std::move(b.s); return *this;
}
};

int main() {
Big a("hello");
Big b = a; // 拷贝构造
std::cout<<"a.s"<<a.s<<std::endl;
std::cout<<"b.s"<<b.s<<std::endl;
Big c = std::move(a); // 移动构造(a.s 资源被搬走)
std::cout<<"c.s"<<c.s<<std::endl;
std::cout<<"a.s"<<a.s<<std::endl;
Big d; d = b; // 拷贝赋值
Big e; e = std::move(b); // 移动赋值
std::cout<<"c.s"<<c.s<<std::endl;
std::cout<<"a.s"<<a.s<<std::endl;
std::cout<<"d.s"<<d.s<<std::endl;
std::cout<<"b.s"<<b.s<<std::endl;
std::cout<<"e.s"<<e.s<<std::endl;
}

运行输出是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Big(string)
Big(const Big&) [copy]
a.shello
b.shello
Big(Big&&) [move]
c.shello
a.s
Big()
operator=(const Big&) [copy assign]
Big()
operator=(Big&&) [move assign]
c.shello
a.s
d.shello
b.s
e.shello

其中对象move之后,它变为“未指定状态”,默认输出可能是空。如果想要指定move之后的值,可以在对象move之后指定。