【问题标题】:C++: What is a de-reference actually doing?C++:取消引用实际上在做什么?
【发布时间】:2017-11-05 20:52:34
【问题描述】:

我正在阅读Stroustrup's 第 4 版:The C++ Programming Language。我有一个python/java 背景,所以到目前为止前 4 章都很好。

Chapter 3我看到了:

complex& operator+=(complex z) { re+=z.re , im+=z.im; return ∗this; }

开始了一天的尝试写这个问题:

首先我发现它返回的是对对象的引用而不是副本。正如我在question 中确认的那样。

而且我能够理解将引用返回到 reference variable 与来自 question 的常规变量之间的区别

我自己做了试验

class Test {
public:

    Test():x{5}{}

    int x;

    void setX(int a) {x = a;}

    Test& operator+=(Test z) {x+=z.x; return *this;}

    // the keyword this is a pointer
    Test* getTest() {return this;}

    // but I can return the reference by *this
    Test& getTest1() {return *this;}

    // or I can return a copy
    Test getTest2() {return *this;}

};

这让我质疑为什么它被称为de-reference,所以我做了这个试验

int x = 8;
int* p = &x;
int y = *p;
int& z = *p;

x++; // let's have some fun

std::cout << y << std::endl;
std::cout << z << std::endl;

正如预期的y = 8z = 9,那么de-reference 如何在一种情况下返回address,而在另一种情况下返回value?更重要的是,C++ 是如何做到这一点的?

【问题讨论】:

  • 引用可以被认为是一个自动取消引用的指针,但它根本不是一个地址。
  • @iksemyonov 如果不是地址或值,那是什么?
  • @SamHammamy 地址就是一个值。
  • @melpomene 内存中的地址是一个值吗?
  • "首先我发现它返回的是对象的地址而不是副本。" - 不,它正在返回对对象的引用。如果它返回一个地址,则返回类型为complex*

标签: c++ reference


【解决方案1】:

这与您的 Test 类函数完全一样。

int y = *p;
int& z = *p;

yp 指向的内容的副本。 zp 指向的引用(不是地址)。所以更改z 更改*p,反之亦然。但是更改y*p 没有影响。

【讨论】:

  • 谢谢!这说明了很多。但是,如果z 不是地址,那么它到底是什么?是的,它是referencex,但它是如何表示的? linux中的符号链接存储目标文件的路径
  • 引用是它们自己的类型。引用和指针之间的区别是微妙的。一个显着的区别是指针可以为 NULL 而引用不能。有关更多详细信息,请参阅此帖子。 stackoverflow.com/questions/57483/…
  • @MFisherKDX IIRC 引用 supposed 永远不会为空,但在某些情况下(尽管通常是人为的)它们可以被滥用来引用空值(或者至少它是可能在一个版本的 C++ 中)。
【解决方案2】:

正如预期的 y = 8 和 z = 9,那么取消引用如何在一种情况下返回地址,而在另一种情况下返回值?更重要的是,C++ 如何做到这一点?

取消引用返回了在这两种情况下引用的实际事物。所以 C++ 没有区别。不同之处在于对取消引用的结果做了什么。

如果您执行int j = &lt;something&gt;;,那么某事的结果将用于初始化j。由于j 是整数,所以&lt;something&gt; 必须是整数值。

如果你执行int &amp;j = &lt;something&gt;;,那么某些东西的结果仍然用于初始化j。但是现在j是一个整数的引用,而&lt;something&gt;必须是一个整数,而不仅仅是一个整数值。

所以,*this 在这两种情况下所做的都是相同的。使用值的方式不会影响该值的计算方式。但是你如何使用它确实会影响你使用它时发生的事情。并且这两段代码以不同的方式使用取消引用的对象。在一种情况下,取其值。在另一种情况下,引用绑定到它。

【讨论】:

  • 谢谢大卫!那么这是否意味着我可以做到int &amp;j = some_function:不是return,而是name of the function?这样我以后可以j() 吗?
  • @SamHammamy 不,因为函数不是对 int 的引用。由于j 是“对int 的引用”类型,所以= 右侧的东西必须是(或可转换为)对整数的引用,而不是函数。此外,对整数的引用是不可调用的。所以j() 没有意义。
【解决方案3】:

可以将指针int* p 视为指向int 类型的数据所在的地址。当您取消引用它时,系统会检索该内存地址的值(该地址是p 本身的实际值)。在int y = *p; 的情况下,您将int 值的副本作为locator value y 放在堆栈上。

另一方面,在*p = 13; 的左侧取消引用意味着您正在将int*p 存储在由p 的值表示的内存地址处替换为右侧-手边值13

int&amp; z = *p; 中的引用左值 int&amp; z不是p 指向的 int 值的副本,而是对特定位置的左侧引用*p 返回的内存地址(即p 本身持有的实际值)。

这在您设计的情况下并没有太大的区别,但是例如给定一个具有Foo::incrementCount() 值的Foo 类,

Foo* p = new Foo();
p->incrementCount();

Foo& ref = *p;
ref.incrementCount();

同一个实例的同一个方法会被调用两次。相反,Foo foo = *p 实际上会复制整个Foo 实例,在堆栈上创建一个单独的副本。因此,调用foo.incrementValue() 不会影响p 仍指向的单独对象。

【讨论】:

    猜你喜欢
    • 2011-08-07
    • 1970-01-01
    • 2015-01-25
    • 2013-06-02
    • 2020-11-21
    • 2015-02-26
    • 2017-06-29
    • 2013-06-13
    • 2021-10-25
    相关资源
    最近更新 更多