是否可以在没有指针的情况下实现引用传递
Could Pass-by-Reference be implemented without pointers?
这可能是一个关于计算机体系结构的问题,而不是c++本身的问题,但我想知道在像c++这样的语言中,如果不使用指针,理论上是否可以实现引用传递。
下面是三个具有类似功能和结构的代码示例。
//Version 1: Uses global variable
#include <iostream>
int global_var = 0;
int increment(void) {return ++global_var;}
int main(void)
{
while (global_var < 100)
printf("Counter: %in", increment());
return 0;
}
//Version 2: Uses pass-by-pointer
#include <iostream>
int increment(int* ptr) {return ++(*ptr);}
int main(void)
{
int local_var = 0;
while (local_var < 100)
printf("Counter: %in", increment(&local_var));
return 0;
}
//Version 3: Uses pass-by-reference
#include <iostream>
int increment(int& ref) {return ++ref;}
int main(void)
{
int local_var = 0;
while (local_var < 100)
printf("Counter: %in", increment(local_var));
return 0;
}
我的猜测是第一个版本中的增量函数直接访问全局变量,没有任何指针。第二个版本在函数的堆栈帧中分配一个指向局部变量的指针,并间接访问它。通过快速搜索,第三个版本显然与第二个版本完全相同(无论如何,在优化之前)。来源:引用是如何在内部实现的?
但是在理论上 (甚至在实践中,经过一些编译器优化后),第三个函数可以直接访问自己的堆栈帧外的局部变量而不需要指针吗?或者这种行为专属于全局变量,因为它们在内存中的位置是静态的?
我问这个问题是因为我认为创建和解引用指针应该占用小的时间和内存量。在传递12个引用的深层递归函数中,时间和内存可能会累积起来。注:我还应该特别提到内联函数,因为它们甚至不生成新的堆栈框架。也就是说,如果函数是inline int increment(int*)
和inline int increment(int&)
,版本2和3的汇编代码会有所不同吗?或者编译器会在这种情况下优化指针吗?
由于不同的编译器可以处理不同的代码,因此我将向您展示msvc++如何处理以下代码的示例:
#include <iostream>
__declspec(noinline) int Increament(int* p)
{
std::cout << "Increament Pointer called" << std::endl;
++*p;
return *p;
}
__declspec(noinline) int Increament(int& p)
{
std::cout << "Increament Reference called" << std::endl;
++p;
return p;
}
int main()
{
int x = 10;
Increament(x);
Increament(&x);
std::cin.get();
return 0;
}
可以看到,两个版本的increment()产生完全相同的代码,它将x的有效地址加载到寄存器eax中,并将该地址压入堆栈。
int x = 10;
00A52598 mov dword ptr [x],0Ah
Increament(x);
00A5259F lea eax,[x]
Increament(x);
00A525A2 push eax
00A525A3 call Increament (0A5135Ch)
00A525A8 add esp,4
Increament(&x);
00A525AB lea eax,[x]
00A525AE push eax
00A525AF call Increament (0A51357h)
00A525B4 add esp,4
至于你的其他问题,编译器可以自由地做任何它喜欢做的事情,结果会彼此不同。
我发布这篇文章的原因是为了让你明白,在asm中没有引用,引用被视为指针,就编译器而言,事实上,引用是带有限制的指针,在c++中设计略有不同。
由于评论中的一些问题而更新:
使用全局变量是否会产生不同的程序集输出
1)代码中的第一个示例将产生不同的汇编,因为global_var是全局的,并且正在初始化,这将把它存储在数据段中。
让我们看一下:
#include <iostream>
int global_var = 50;
__declspec(noinline) int increment(void)
{
++global_var;
return global_var;
}
int main(void)
{
increment();
std::cin.get();
return 0;
}
为函数生成以下程序集,注意这里没有push任何内容:
00A61000 mov eax,dword ptr ds:[00A63018h]
00A61005 inc eax
00A61006 mov dword ptr ds:[00A63018h],eax
0x00A63018是内存中global_var的地址,它的值被存储在eax中,递增并恢复到旧的内存位置。
我不明白你的问题。你可以有全局引用,根据规则,它必须直接指向某些东西:例如,另一个初始化的变量,它将以相同的方式运行,除了保存一个值50,它将保存另一个全局变量的地址。基本上不可能以同样的方式实现引用作为全局变量(即不带指针访问它们)
。在没有指针的情况下访问它们
这部分是什么让我困惑,这是没有意义的时候谈论参考。你不能通过指针访问引用,这在c++中是不可能的。你甚至不能得到一个参考的地址。
引用,像其他所有东西一样,通常在汇编语言内部实现,而不是作为C代码实现。
大多数汇编语言通过地址访问所有内容(即使是编译根本不使用指针或引用的C代码的结果),除了寄存器中有内容的短暂时间。
- 在没有未定义行为的情况下实现类似std::vector的容器
- C++标准是否允许<double>在没有开销的情况下实现 std::可选
- 我可以在没有堆栈的情况下在二叉搜索树中实现迭代器吗?
- 如何在编译器C++不智能的情况下实现 GLSL vec* 构造语法?
- 为什么在这种情况下不调用我的虚拟函数实现?
- 我们可以在不使用head指针的情况下通过使用head的简单变量而不是head的指针来实现链表吗
- 在确定有实现的情况下获取HTTP 501未实现
- 在不创建新节点的情况下实现带有映射的trie
- 在这种情况下,有什么正确的方法可以实现锁定吗?
- 如何在不停滞主循环的情况下实现对话系统?
- 如何在不引入未来对象切片的情况下实现 ICloneable
- 是否可以在不依赖内置编译器的情况下拥有is_trivially_constructible的库实现
- 如何在没有参数的情况下实现返回双向链表大小的函数?int size() const.
- 有没有办法在不重新实现的情况下从子类中标记父级的虚拟函数 final。
- 如何在不使用函数或类的情况下重复代码段,以便在C++中实现高性能循环
- 在C++中,我不能在不分离标头和 cpp 的情况下实现此类吗?
- 在没有限定的情况下从 T 构造函数调用类 T 的纯虚拟实现?
- 如何在不修改C 中的LHS参数的情况下实现` `运算符
- 如何在不使用 lambda 表达式的情况下实现特定的比较器
- 如何在不必绑定到特定类的情况下实现观察者模式