7 reference、const、new/delete
7.1 reference
x
是整数,占4字节;p
是指针占4字节(32位);r
代表x
,那么r
也是整数,占4字节
int x = 0;
int* p = &x; // 地址和指针是互通的
int& r = x; // 引用是代表x
引用与指针不同,只能代表一个变量,不能改变
引用底部的实现也是指针,但是注意 object 和它的 reference 的大小是相同的,地址也是相同的(是编译器制造的假象)
sizeof(r) == sizeof(x) &x == &r
reference 通常不用于声明变量,用于参数类型和返回类型的描述
以下 imag(const double& im)
和 imag(const double im)
的签名signature 在C++中是视为相同的——二者不能同时存在
double imag(const double& im) /*const*/ {....}
double imag(const double im){....} //Ambiguity
注意:const 是函数签名的一部分,所以加上后是可以共存的
7.2 const
const
加在函数后面 —— 常量成员函数(成员函数才有):表示这个成员函数保证不改变 class 的 data
const object | non-const object | |
---|---|---|
const member function(保证不改变 data members) | ✔️ | ✔️ |
non-const member function(不保证 data members 不变) | ❌ | ✔️ |
COW:Copy On Write
多个指针共享一个 “Hello”;但当a要改变内容时, 系统会单独复制一份出来给a来改,即 COW
在常量成员函数中,数据不能被改变所以不需要COW;而非常量成员函数中数据就有可能被改变,需要COW
charT
operator[] (size_type pos)const
{
.... /* 不必考虑COW */
}
reference
operator[] (size_type pos)
{
.... /* 必须考虑COW */
}
函数签名不包括返回类型但包括
const
,所以上面两个函数是共存的
当两个版本同时存在时,const object 只能调用 const 版本,non-const object 只能调用 non-const 版本
7.3 new delete
7.3.1 全局重载
- 可以全局重载
operator new
、operator delete
、operator new[]
、operator delete[]
- 这几个函数是在 new 的时候,编译器的分解步骤中的函数,是给编译器调用的
注意这个影响非常大!
inline void* operator new(size_t size){....}
inline void* operator new[](size_t size){....}
inline void operator delete(void* ptr){....}
inline void operator delete[](void* ptr){....}
7.3.2 class中成员重载
- 可以重载 class 中成员函数
operator new
、operator delete
、operator new[]
、operator delete[]
- 重载之后,new 这个类时,编译器会使用重载之后的
class Foo
{
public:
void* operator new(size_t size){....}
void operator delete(void* ptr, size_t size){....} // size_t可有可无
void* operator new[](size_t size){....}
void operator delete[](void* ptr, size_t size){....} // size_t可有可无
....
}
// 这里优先调用 members,若无就调用 globals
Foo* pf = new Foo;
delete pf;
// 这里强制调用 globals
Foo* pf = ::new Foo;
::delete pf;
7.3.3 placement new delete
可以重载 class 成员函数 placement new operator new()
,可以写出多个版本,前提是每一个版本的声明有独特的传入参数列,且其中第一个参数必须是 size_t,其余参数出现于 new(.....)
小括号内(即 placement arguments)
Foo* pf = new(300, 'c') Foo; // 其中第一个参数size_t不用写
// 对应的operator new
void* operator new (size_t size, long extra, char init){....}
我们也可以重载对应的 class 成员函数 operator delete()
,但其不会被delete调用,只当 new 调用的构造函数抛出异常 exception 的时候,才会调用来归还未能完全创建成功的 object 占用的内存