请问在这种情况下,“引用”和“指针”的区别是什么?

6

当我阅读这个问题的litb答案时,我了解到通过引用传递数组可以获取其大小。我尝试通过引用传递一个“函数”,令人惊讶的是(至少对我来说),这段代码可以编译:

void execute( void (&func)() ) // func is passed by reference!
{
    func();
}

这两个函数有什么不同:

void execute( void (*func)() ) // func is passed by pointer!
{
    func();
}

我使用VC2008尝试了这个问题,每种情况下输出都不同。奇怪的是,在函数指针的情况下,编译器可以更好地优化代码:

void print()
{
    std::cout << "Hello References!";
}
void execute( void (&func)() ) // optimized
{
    func();
}
int main()
{
    00291020  call   print (291000h)
}
=========================================
// In this case, the compiler removes all function calls in the code!
void print() // optimized!
{
    std::cout << "Hello Pointers!";
}
void execute( void (*func)() ) // optimized
{
    func();
}
int main()
{
    002F1005  push  offset string "Hello References!" (2F2124h) 
    002F100A  push  eax  
    002F100B  call  std::operator<<<std::char_traits<char> > (2F1150h) 
}

虽然我看不出来,但一定有区别吧?

注意:使用VC2008编译代码,并开启了/O2/Ot选项。


编辑:我非常想知道函数引用和函数指针之间的区别。我检查了生成的汇编代码,只是为了看看在每种情况下它是如何转换的。


你只是对优化器的行为感兴趣还是对一般的函数参考信息感兴趣? - Johannes Schaub - litb
@litb,我真的很惊讶我可以通过引用传递函数。如果您能解释一下与函数指针的功能或其他方面的区别,那就太好了 :) - Khaled Alshaya
4个回答

3

针对语言差异(仅保留以下函数声明,因为这是最重要的部分)

void execute( void (&func)() );

void g();
int main() {
  void (*fp)() = g;
  execute(fp); // doesn't work
  execute(&g); // doesn't work either
  execute(g); // works
}

它不能工作,因为它需要一个函数而不是一个函数指针。与数组拒绝指针的原因相同,这也拒绝了一个指针。您必须直接传递"g"。

对于模板,这也很重要。

template<typename T>
void execute(T &t) { T u = t; u(); }

template<typename T>
void execute(T t) { T u = t; u(); }

这两者非常不同。如果您像上面那样使用execute(g);进行调用,则第一个将尝试声明一个函数并使用t(引用g)进行初始化。生成的函数将如下所示:

void execute(void(&t)()) { void u() = t; u(); }

现在您可以初始化对函数的引用和指针,但当然不能初始化函数本身。在第二个定义中,通过模板参数推导,T将被推导为函数指针类型,并且传递函数将隐式转换为该指针参数类型。所以一切都会很好。
我不知道为什么MSVC在内联方面对它们进行了不同的处理 - 但我也怀疑这是因为函数引用出现得更少。

execute(*fp); 这个怎么样呢,这是第四种情况的缺失 :-) - Kerrek SB

3

这不是一个常见的习语,所以可能只是因为VS团队没有添加优化规则。


3

我认为这是由于C++标准4.3所规定的:

函数类型T的左值可以转换为类型“指向T的指针”的右值。结果是指向该函数的指针。


有趣的引用。这是否意味着在转换函数引用后,基本上两种情况下都应该生成相同的代码。我知道这是一个实现细节,但如果它被转换,编译器如何优化指针而不是引用? - Khaled Alshaya

-2
引用(&)和指针(*)之间的区别在于,引用提供变量或位置的地址,而指针指向存储在其中的地址在内存中的位置。
int *pointer;
int variable;

pointer = &variable; // assigning the address of variable to pointer 

variable = 53;  // value of variable

cout << *pointer; // This should output the value of the address where is pointing, in this
                  //  case 53, that is the value of variable to where is pointing.

我们可以得出结论,(&variable) 拥有该内存位置的地址,而 *anyname 指向其存储在内存中的地址...

“引用提供变量或位置的地址,指针指向存储在其中的地址在内存中的位置。” 哦...我认为您将引用与取地址运算符混淆了。 - Lightness Races in Orbit

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接