0

我们都知道,在 C++ 中定义新实例的最简单方法是下一个:

ClassName *obj = new ClassName();

但是这种方法很糟糕,更高级的人使用智能指针,例如:shared_ptrunique_ptr...但是如果查看他们的来源,您可能会发现 smart_pointers 使用指针来创建新实例,而不是引用。

我也知道,使用指针不仅对 C++ 中的干净源代码(设计规则)不利,而且指针也会分配新内存,因为任何指针都是一种void*类型。正确的大小取决于 CPU 架构,但对于示例,让我们以 x86 为例,它拥有 4 个字节。

使用起来比使用引用要昂贵得多,引用&不需要为它们分配任何内存,这就是为什么在 C++ 自定义方法中使用引用要好得多。

所以告诉你所有这些信息,我想知道:

是否可以在 C++ 中使用引用定义新实例?如果不是,那为什么?

4

6 回答 6

6

恐怕你的帖子是一个接一个的误解。所以你要做的第一件事就是扔掉你读过的所有“书”,读一本关于 C++ 的好书

现在,试着回答你的问题。您不能“通过引用”创建对象。相反,您可以创建对现有对象的引用。

MyClass myobject;
MyClass& myreference = myobject;

就像您可以创建一个指向现有对象(或不指向任何对象)的指针一样。请注意,创建对象的不是指针。新表达式会:

new MyClass;

如果愿意的话,“在堆上”创建了一个 MyClass 类型的新对象。但它毫无用处,因为你已经失去了它的所有句柄。您无法访问它。这就是为什么我们将这个对象的地址(new 返回的)存储在一个指针中。如果它是智能指针而不是普通指针,它将自动“知道”何时释放内存,即删除对象,具体取决于智能指针的类型。这就是说,您可以创建对它的引用,而不是存储新创建对象的地址:

MyClass& ref = *new MyClass;
...
delete &ref;

引用是免费的(就内存而言)也是不正确的。当然, sizeof(reference) 将返回所引用对象的大小,但大多数实现将在底层使用指针式逻辑来进行引用。

于 2013-07-06T10:35:50.357 回答
2
ClassName *obj = new ClassName();

这不是最简单的方法。这是 :

ClassName obj;

而且由于引用是……嗯,引用,您必须实例化一个对象才能获得引用。

ClassName obj;
ClassName& refObj = obj;

如果没有要引用的对象,就无法创建要使用的引用。

于 2013-07-06T10:34:51.353 回答
2

我们都知道,在 C++ 中定义新实例的最简单方法是下一个:

ClassName *obj = new ClassName();

不,我们不……因为它不是。

要创建 type 的新实例ClassName,只需编写:

ClassName obj;

仅在需要时使用动态分配!

但是这种方法很糟糕,更高级的人使用智能指针,例如:shared_ptr、unique_ptr 等...但是如果查看它们的来源,您可能会发现 smart_pointers 使用指针来创建新实例,而不是引用。我也知道,使用指针不仅对 C++ 中的干净源代码不利(设计规则)

有哪些设计规则?没有“规则”,只有不同的人写的不同的指导方针,都有自己的观点。

通常建议避免使用指针,因为它们的使用意味着动态分配,这更难管理。智能指针确实对此有所帮助,但它们不是使用动态分配的理由,否则您不会这样做。

指针也会分配新内存,因为任何指针都是 void* 类型。正确的大小取决于 CPU 架构,但对于示例,让我们以 x86 为例,它拥有 4 个字节。

嗯,这也不是真的。每个指针类型都是它自己的类型,它们不一定都是相同的宽度。但是,通常情况下可能会出现这种情况。

使用起来比使用引用 & 更昂贵,因为引用 & 不需要为它们分配任何内存,这就是为什么在 C++ 自定义方法中使用引用要好得多。

不,也不是真的。C++ 中的引用语法通过透明地执行它们来隐藏取消引用操作,但是您会发现所有实现/工具链/编译器无论如何都使用指针来实现引用。

您应该停止考虑“指针”与“引用”。也许您正在考虑 Java。

您应该考虑自动存储持续时间(“堆栈”)与动态存储持续时间(“堆”) - 前者效率更高,因为它不需要动态分配,但您失去了精细控制对象生命周期的能力.

是否可以在 C++ 中使用引用定义新实例?如果不是,那为什么?

如果您的意思是“如何在没有动态分配的情况下创建对象”,请参阅以下示例:

// automatic storage duration - cheap!
ClassName obj;

// dynamic storage duration - marginally more expensive,
// and now you have to `delete` it, too
ClassName* ptr = new ClassName;

在 C++ 中,引用就像一个“自动指针”;它做同样的工作,但没有所有的语法要求:

ClassName* ptr = &obj;  // a pointer to obj
ClassName& ref = obj;   // a reference to obj

new运算符始终为您提供指向动态分配对象的指针,而不是引用。这就是它的方式。

于 2013-07-06T13:33:30.047 回答
1

我们都知道,在 C++ 中定义新实例的最简单方法是下一个:

不!创建实例的最简单方法是:

ClassName obj;

要为此初始化引用,只需说:

ClassName& objRef = obj;

或者

const ClassName& constObjRef = obj;

使用引用作为函数的返回值时要小心。当函数离开其作用域时,您应该确保引用的对象实例仍然存在。

于 2013-07-06T10:34:27.703 回答
1

我认为纠正你帖子中不同的错误断言是值得的(除了回答主要问题),这样你就可以回到正确的轨道上。

定义新实例的最简单方法是A * a = new A();

不,最简单的方法是A a;

这种方式不好,所以更高级的人使用智能指针

确实,这不是最推荐的。主要缺点是:

  1. 对象在堆上分配,这使得访问速度变慢。

  2. 您必须通过显式调用自己来管理内存delete

使用智能指针只能解决第 2 点。这就是为什么更高级的人实际上会在堆栈上使用尽可能多的分配,使用A a;. 然而,这并不总是可能的,在这种情况下,智能指针确实是最好的选择。

但是智能指针使用的是指针,而不是引用!

实际上,智能指针的目的只是为了帮助进行内存管理(这就是标题为 的原因#include <memory>),因此它们确实处理堆上的对象,而不是堆栈上的对象。他们所做的是在呼唤delete您,因此您不必担心内存泄漏。

指针不好,因为任何指针都是 void* 类型,需要内存

是的,指针占用堆栈中的 N 位内存(N=32 或 64,具体取决于您的架构)+堆中对象的实际大小 S。但这也适用于参考!不同类型实体所需空间的摘要:

  • 指针( A * a = new A;):堆栈上的 N 位(地址)+堆上的 S 位(对象)

  • 引用( A a; A &ref = a;):堆栈上的 N 位(地址)+ 堆栈上的 S 位(对象)

  • 直接值( A a;):堆栈上的 S 位(对象)

因此,从内存空间的角度来看,引用和指针是相同的,只有在堆栈上使用直接值才会有所收获。请注意,实际上,引用也可以指向堆上的对象(A &ref = *new A;),指针也可以指向堆栈上的对象(A a; A * ptr = &a;)。

是否可以在 C++ 中使用引用定义新实例?

是的:

A a; 
A &ref = a;
于 2013-07-06T12:17:16.290 回答
0

在 C++ 中通过引用返回不是一个好主意。(我认为你的意思是这个)。因为,您不能通过引用将局部变量返回给函数。参考链接

int& DoubleValue(int nX)
{
    int nValue = nX * 2;
    return nValue; // return a reference to nValue here
} // nValue goes out of scope here

“......该函数试图返回对一个值的引用,该值将在函数返回时超出范围。这意味着调用者收到对垃圾的引用......”

于 2013-07-06T10:36:11.517 回答