3种构造语义: - 构造函数constructor
- 拷贝构造copy constructor
- 拷贝赋值运算符copy assignment operator
构造函数S() 出厂设置 拷贝构造S(const S &other) 把A的数据复制给B。B(A); 拷贝赋值运算符S& operator=(const S &other) 先把B的资源释放,再把A的数据复制给B。B=A; 变量按内存分为两种: - 不包含指针。trivial type。篮球。
- 包含指针。handle type。风筝和风筝线。
拷贝的分类 - 浅拷贝
引用语意(reference semantics) 缺陷:若写法不对,可能会发生double free。 Q:为什么编译器所有的默认的行为都是浅拷贝? A:深拷贝不一定能实现。指向的对象可能是多态的,也可能是数组,也可能有循环引用。所以只能留待成员变量的类来决定怎样实现复制。 有时候为了防止默认拷贝发生,可以声明一个私有的拷贝构造函数。这种做法比较常见,但不可取。 - 深拷贝
值语意(value semantics) 缺陷:出现了额外的构造和析构,性能损失。 深拷贝和浅拷贝的本质区别就是两个对象的行为属性是否是独立变化的。
C++的第二个坑:拷贝构造函数 思考: T为handle type,T A(...),T B(A)。A赋值给B。如果A不再使用了,能不能让B直接接管A的所有资源呢?(移动语义move semantics) 在不破坏现有语法规则情况下,你会如何设计? - C++03现有语法不支持移动语义。需要新增移动语义。
- 如何标识对象的资源是可以被移动的呢?
- 这种机制必须以一种最低开销的方式实现,并且对所有的类都有效。
- 设计在编译层,与运行层面无关。
C++的设计者们注意到,大多数情况下,右值所包含的对象都是可以安全的被移动的。 左值与右值左值和右值的概念 CPL语言引入了表达式值的类型value categories这种概念:左值和右值,left or right of assignment。 C语言沿用了类似的分类:左值和其他,locator value and other C++98 沿用了C语言的分类,但是略微调整。引入了新定义:右值rvalue = non-lvalue。 C++11 新增了xvalue(an “eXpiring” value),并调整了之前左值和右值的定义。
 (i)has identity: it's possible to determine whether the expression refers to the same entity as another expression, such as by comparing addresses of the objects or the functions they identify (obtained directly or indirectly); (m)can be moved from: move constructor, move assignment operator, or another function overload that implements move semantics can bind to the expression. 准则 1:能不能分辨两个表达式指的是同一个物体。比如我们可以通过比较地址。 准则 2:能不能使用移动语义。比如看看能不能用调用移动构造函数。 - i&~m:lvalue 左值
- i&m:xvalue 将亡值
- ~i&m:prvalue 纯右值
- i:glvalue泛左值
- m:rvalue右值
C++17 分类和 C++11 是一样的,但是语义上更加明确了。 - glvalues:有自己地址的长寿对象
- prvalues:为了初始化而用的短命对象
- xvalue:资源已经不需要了,而且可以再利用的长寿对象
为了优化这样一个情况:T(T(T(x)))==>T(x),将prvalues的定义略微调整了下。 具体可以参考Copy elision (复制消除) |