【问题标题】:Is there any point of "reference of pointer"?有没有“指针引用”的点?
【发布时间】:2021-08-08 11:12:03
【问题描述】:

我不明白指针类型的引用是如何工作的。

  1. 有什么性能差异吗?

  2. 如果他们编译有任何汇编级别的差异吗?

  3. 指针类型有什么引用点吗?

vector<Figure*> vFigureList;

//auto&
for(auto& pFigure : vFigureList)
{
    pFigure->draw();
    delete pFigure;
}

//auto
for(auto pFigure : vFigureList)
{
    pFigure->draw();
    delete pFigure;
}

//Figure*
for(Figure* pFigure : vFigureList)
{
    pFigure->draw();
    delete pFigure;
}

//Figure*&
for(Figure*& pFigure : vFigureList)
{
    pFigure->draw();
    delete pFigure;
}

【问题讨论】:

  • 在你的例子中,当你使用引用时,你告诉编译器:我的意思是那个!当不使用引用时,你告诉它:I意思是那个副本!这是两个非常不同的东西。

标签: c++ pointers reference pass-by-reference auto


【解决方案1】:
  1. 有指针类型的引用点吗?

当你想对它们进行修改时。例如

// when modify pointers themselves in vFigureList
for(auto& pFigure : vFigureList)
{
    delete pFigure;
    pFigure = nullptr; // modify pointers (in vFigureList) to nullptr
}

基本上和intint&amp;的区别是一样的。

【讨论】:

  • 也许是个挑剔的人,但仍然:与 for( auto pFigure : vFigureList ) 相比有什么区别?在问题的 sn-p 中,普通指针将具有相同的语义,对吧?
  • @André Given for( auto pFigure : vFigureList ), pFigure 是一个副本,对它的任何修改都与vFigureList 中的指针无关。
  • 对不起,我错过了你的pFigure = nullptr。你当然是对的。对于删除无关紧要,因为这将适用于指针的任何副本。但是必须在列表中的实际指针上完成对nullptr 的重置。也许您也可以在答案中澄清这一点;-)?
【解决方案2】:

引用往往以指针的形式实现,因此您的 Figure*&amp; 本质上是一个指向指针的指针。

有什么性能差异吗?

如果编译的话,有什么汇编级别的区别吗?

在使用之前需要取消引用,但具体细节取决于实现。在您的示例中,您的编译器更有可能完全优化它并直接访问/修改向量中的值。在这种情况下,pFigure(即使是一个值)可​​能真的是一个别名,根本没有映射到任何物理变量。

指针类型有什么引用点吗?

除非您想直接修改指针本身,否则不会,正如其他答案已经指出的那样。

【讨论】:

    【解决方案3】:

    一旦编译,引用就像指针一样,它们提供了一定程度的间接性。但是它们在 C++ 中有不同的用途:

    • 它们必须在定义时进行初始化,因此更安全,就像 const 指针一样。
    • 无需使用&amp;运算符的地址来声明它们指向的位置。
    • 使用* 无需遵从。

    有什么性能差异吗?

    是的,引用会产生一定程度的指针取消引用,就像普通指针一样。

    如果编译的话,有什么汇编级别的区别吗?

    与普通变量相比,是的,额外的间接级别。与指针相比,不,引用和指针编译后是一样的。

    指针类型有什么引用点吗?

    是的,如果您需要一个指向指针的指针,但又想要引用的安全性和便利性。

    这是 Compiler Explorer 上的一个示例(如果链接过期,请参见下面的相同来源): https://godbolt.org/z/h3WzdPWa1

    在没有优化的情况下编译时(不推荐,仅用于此 Compiler Explorer 示例的说明):

    • 直接访问使用三个汇编指令
    • 一级间接(指针和引用)使用五个指令
    • 两级间接(对指针的引用和对指针的指针)使用七条指令

    这有助于说明引用实际上是底层的指针,具有相同的性能影响。

    int num();
    int* num_ptr();
    
    int main() {
        int i = num();
        
        int& r = i;
        int* p = num_ptr();
    
        int*& pr = p;
        int** pp = &p;
    
        // Direct access
        i += 3;
    
        // One level of indirection
        r += 5;   
        *p += 7;
    
        // Two levels of indirection
        *pr += 11;
        **pp += 13;
    
        return 0;
    }
    

    【讨论】:

    • “编译时没有优化”是一个非常糟糕的指示。例如,许多优化器都知道您没有提到的另一条规则:有空指针,但没有空引用。
    • 同意,优化会提高性能。仅在此 Compiler Explorer 示例的上下文中未提及优化以说明间接级别。启用优化后,即使只是 -O1,GCC 也会丢弃 num() 结果并查看所有指针访问并直接跳到将 31 添加到 num_ptr() 的结果。
    猜你喜欢
    • 1970-01-01
    • 2011-03-23
    • 1970-01-01
    • 2016-01-12
    • 1970-01-01
    • 2021-01-15
    • 1970-01-01
    • 1970-01-01
    • 2011-06-17
    相关资源
    最近更新 更多