C++:动态内存的引用

yyhrrdl8  于 2023-04-01  发布在  其他
关注(0)|答案(4)|浏览(68)

除了考虑什么时候使用which之外,我仍然不确定指针和引用的语义。
现在,我的印象是引用本质上是指针,必须在声明它们时初始化,然后从那时起不能指向任何其他东西。(不是Type const*),或者,它们不能被 * 重新赋值 *。它本质上变成了那个对象的“新名称”。现在我听说引用实际上不需要由编译器使用指针来实现,但我的印象是,你仍然可以这样想他们,关于他们的可见行为将是什么。
但你为什么不能做这样的事:

int& foo = new int;

我想创建一个对动态内存的引用。这不能编译。我得到错误

error: invalid initialization of non-const reference of type 'int&' from a temporary of type 'int*'

这对我来说是有意义的。似乎new操作符返回一个给定类型的指针,指向操作系统动态分配给我的内存地址。
那么,如何创建对动态内存的“引用”呢?
编辑:如果能提供精确解释C++中引用和指针之间区别的资源链接,我们将不胜感激。

rks48beu

rks48beu1#

new返回一个指向已分配内存的指针,因此需要在指针中捕获返回值。
你可以在分配完成后创建一个指针的引用。

int *ptr = new int;
int* &ref = ptr;

然后在使用后将其删除为:

delete ref;

或者更简单地,

int &ref = *(new int);

使用后删除:

delete &ref;
qfe3c7zg

qfe3c7zg2#

引用是语法糖,它允许使用点操作符而不是箭头来访问对象。
你选择使用指针还是引用是 * 语义 * 的。当你通过引用传递一个对象给一个方法,或者从一个方法返回一个引用时,你是在说:“这是我的对象,你可以使用它,但我拥有它(它可能在堆栈或堆上)。”因此,这里的其他答案建议像delete &foo;这样的语法可能在技术上可行,但味道不好;如果你有一个对象的引用,那么你不应该删除它。你不拥有它,最重要的是,因为你不能重置引用,你最终会得到一个对释放内存的引用,这是一件坏事。
现在,如果你已经在堆上分配了一个对象(称为'new'来创建它),那么你确实拥有它,并且负责稍后清理它,所以你需要持有一个指向它的指针。为什么?这样你就可以安全地删除它并将指针空出来。
指针和引用之间的区别,除了使用点而不是箭头的机械区别之外,就是通过引用传递给方法,你指示了应该如何使用对象。通过调用new直接初始化引用是毫无意义的,即使可能。

iqjalb3h

iqjalb3h3#

你可以得到这样的引用:

int& foo = *(new int);

一般来说,要从T*获取到T&,您可以使用*来“解引用”指针。
然而这并不是一个好主意,你通常使用指针来存储堆分配对象的地址。

utugiqy6

utugiqy64#

如何引用数组

通过数组引用,我将一个堆栈数组变成了一个堆数组,而不需要大量重写我的软件。总共更改了三行代码,在类声明,构造函数和析构函数中。

栈版本

bool removed [arraySize];

heap版本

bool(&removed)[arraySize];
Sieve::Sieve() : removed( * (bool(*)[arraySize]) (new bool[arraySize]) )
delete [] (&removed);

详细说明

不要因为别人告诉你如何编写软件而感到厌烦,比如说“不要那样做”。他们的方式可能更好,但这是你自己的决定,告诉你不要做某件事并不是对“我怎么能做?"这个问题的回答,即使你想做的事情很糟糕。
我来这里寻找一个快速解决我的问题的方法。我写了一个Eratosthenese程序作为基准程序来测试我自己的素数生成器,并让它在小数字上工作得很好,以检查它的操作。我扩大了筛数组的大小,以计算更多的素数,并有堆栈大小的问题,正如我们可能预料到的那样。我想取代

private:
    bool removed [arraySize];

简单的

private:
    bool(&removed)[arraySize];

这样,一旦我从new语句(在我的Sieve类构造函数中)初始化了reference,当然也用delete(在类析构函数中)整理好了,整个工作软件就可以不加修改地继续工作。
我反对被告知我太懒了,不能用-〉替换.,并且应该在整个软件中使用指针。作为我类的私有成员,我可以在没有. or -〉的情况下访问数据,非常感谢!我不想重写我的成员函数访问数据,只是因为我从堆栈上的数组切换到堆上的数组。
所以,让我们分解一下我从堆栈数组切换到堆数组所做的事情,使用数组引用来避免主要的rewite。

(new bool[arraySize])

这是一个新的指针,指向堆上新创建的数组。

(bool(*)[arraySize]

是指针的类型:一个指向所需大小的布尔数组的指针。
要初始化我的引用成员,我需要在构造函数的成员初始化列表中进行……

Sieve::Sieve() : removed( ... )

其中上面的...是引用需要初始化的对象。我们即将谈到这一点,所以请耐心等待一会儿。引用通过使用对象初始化,编译器找到它的地址。由于我们有指针,我们需要使用*来引用new找到的对象,而不是它的地址。
因此,将查找指针与new结合起来,将其转换为正确的类型,然后获取它所指向的对象,我们有

* (bool(*)[arraySize]) (new bool[arraySize])

这是类成员初始化列表中所需的内容:我们上面的...。所以我们有

Sieve::Sieve() : removed( * (bool(*)[arraySize]) (new bool[arraySize]) )

在析构函数中需要相反的方法。数组需要是delete d。

delete [] ...

其中,...new返回的指针值相同。
在我们的例子中它是引用数组的地址

(&removed)

所以我们有

delete [] (&removed);

相关问题