一直有一个困惑,引用就是对象一个别名,别人问引用和指针区别?隐藏引用就不是指针
并且很多例子,参数传递和构造函数,看很多八股文, 到底一样不一样,课本上没有说,很模糊,不分配怎么操作。
直觉,感觉上判断,肯定有,如果没有。怎么被使用呢
这样认知陷入了矛盾:感觉上判断,肯定有,但是课本上没说,感觉痛苦难受!!!
为此展开了调查。
------->>指针-->>-----引用------->
从c++发展历史来看,先出现指针( go也有指针类,没有引用类),后又引用,
因此引用这个概念技术对指针高级封装。
我推测对引用操作,就是对对象的操作,一定是做一封封装,就像写函数一样。
这样合情合理,顿时感觉完美来了!
从汇编角度看 指针和引用变量初始化产生汇编代码是一样的【都是三行】
int a = 3;
int &ra = a;
int b = 4;
int *pa = &b;
int a = 3;
int &ra = a;
012E33F8 mov dword ptr [a],3
012E33FF lea eax,[a]
012E3402 mov dword ptr [ra],eax
int b = 4;
int *pa = &b;
012E3405 mov dword ptr [b],4
012E340C lea eax,[b]
012E340F mov dword ptr [pa],eax
而 b 和 pa 也同样是这样步骤。
int a = 3;
012E33F8 mov dword ptr [a],3 //把 3 放入地址为 [a] 的内存
int &ra = a;
012E33FF lea eax,[a] //a 的地址放入 eax
012E3402 mov dword ptr [ra],eax ,//最后把 eax 的值放入地址为 [ra] 的内存
//实际上,就是把 a 的地址放入了 ra 里。
int b = 4;
012E3405 mov dword ptr [b],4 // 把 4放入地址为 [b] 的内存
int *pa = &b;
012E340C lea eax,[b] //b 的地址放入 eax
012E340F mov dword ptr [pa],eax ,//最后把 eax 的值放入地址为 [pa] 的内存
从汇编的角度来看,引用是通过指针来实现的
ra++;
(*pa)++;
(*pa)++;
013F4498 mov eax,dword ptr [pa]
013F449B mov ecx,dword ptr [eax]
013F449D add ecx,1
013F44A0 mov edx,dword ptr [pa]
013F44A3 mov dword ptr [edx],ecx
ra++;
013F4475 mov eax,dword ptr [ra]
013F4478 mov ecx,dword ptr [eax]
013F447A add ecx,1
013F447D mov edx,dword ptr [ra]
013F4480 mov dword ptr [edx],ecx
ra++;
013F4475 mov eax,dword ptr [ra] //获取rad地址 eax
013F4478 mov ecx,dword ptr [eax] //获取rad地址里的值:对象的地址 ecx
013F447A add ecx,1 //在寄存器完成计算 ecx
013F447D mov edx,dword ptr [ra] //获取rad地址里的值:对象的地址 edx
013F4480 mov dword ptr [edx],ecx //写回到 原来对象里面
#include <iostream>
#include <string.h>
using namespace std;
class Base
{
public:
virtual ~Base(){}
private:
int data;
};
class Test
{
public:
Base* m_ptr;
Base &m_base;
public:
Test( Base& base):m_base(base),m_ptr(&base)
{
cout<< m_ptr<<endl;
cout<< &m_base<<endl;
//Test( Base &base):m_base(&base),m_ptr(&base)
//invalid initialization of non-const reference of type ‘Base&’ from a temporary of type ‘Base*’
}
};
void test_ref()
{
Base base;
Test a(base);
cout << "sizeof(base)=" <<sizeof(base) <<endl; //16
cout << "sizeof(a)=" <<sizeof(a) <<endl;//16 神奇 为是不是24呢?表现出来是指针呢
cout << "sizeof(a._base)=" <<sizeof(a.m_base) <<endl; //16
}
int main()
{
test_ref();
return 0;
}
int a= 10;
int*ptr = &a;
int& b= a;
(gdb) p &a
$11 = (int *) 0x7fffffffe07c
(gdb) p ptr
$12 = (int *) 0x7fffffffe07c
(gdb) p b
$13 = (int &) @0x7fffffffe07c: 10
SudokuServer(EventLoop* loop, const InetAddress& listenAddr)
: server_(loop, listenAddr, "SudokuServer"),
startTime_(Timestamp::now())
{
server_.setConnectionCallback(
std::bind(&SudokuServer::onConnection, this, _1));
server_.setMessageCallback(
std::bind(&SudokuServer::onMessage, this, _1, _2, _3));
}
引用至少解决了两个问题:
Is an Rvalue Reference an Rvalue?
hings that are declared as rvalue reference can be lvalues or rvalues. The distinguishing criterion is: if it has a name, then it is an lvalue. Otherwise, it is an rvalue.
In the example above, the thing that is declared as an rvalue reference has a name, and therefore, it is an lvalue:
//参数有名字,调用X(X const & rhs)
void foo(X&& x)
{
X anotherX = x; // calls X(X const & rhs)
}
Here is an example of something that is declared as an rvalue reference and does not have a name, and is therefore an rvalue:
//返回值没有名字,调用X(X&& rhs)
X&& goo();
X x = goo(); // calls X(X&& rhs) because the thing on
// the right hand side has no name
X& X::operator=(X&& rhs)
{
// Perform a cleanup that takes care of at least those parts of the
// destructor that have side effects. Be sure to leave the object
// in a destructible and assignable state.
// Move semantics: exchange content between this and rhs
return *this;
}
左值和右值的主要区别是,左值可以被修改,而右值不能。不过,C++11 改变了这一区别。在一些特殊的情况下,我们可以使用右值的引用,并对右值进行修改。
Rvalue 并不意味着对象是不可变的