C++中的new和*new有何区别?

15

我这样做:

MyClass myObject = *new MyClass();

但很多人都建议我这样做:

MyClass *myObject = new MyClass();

第二种方法有性能差异或逻辑上的原因吗?我只是喜欢使用第一种方法来消除指针混淆。


25
我有一个问题:“你为什么这样做?”如果你想喝一杯水,你会先去买一个新杯子,把它装满水,再把水倒进旧杯子里,最后扔掉新杯子吗? - Nik Bougalis
2
哇...我很震惊,竟然有人让你用第一种方法。那只是小儿科的东西。Nik的比喻非常恰当。 - Iron Savior
3
如果你曾经提交过包含这种代码的作业,你应该认真要求退款。显然他们没有发现它,或者解释它的作用和为什么你不应该这样做的方法不够有效。 - Captain Obvlious
17
@NikBougalis:好比喻,但他更糟糕:他不会丢掉这个玻璃杯,而是把它遗忘在桌子上。我想知道房子里有多少个杯子! - Emilio Garavaglia
3
仅当复制构造函数可行时,才允许进行 RVO(返回值优化)。 - Flexo
显示剩余5条评论
3个回答

31

两者并不相同!
如果你稍后调用delete,第一个会导致未定义的行为[参考文献1:]或内存泄漏,而第二个则不会。

MyClass myObject = *new MyClass();

在堆上分配一个MyClass类型的对象,然后将该对象复制到myObject中。您丢失了指向动态分配对象的指针,因此永远无法将其释放。
如果MyClass析构函数具有副作用,并且您的程序依赖于这些副作用,则如果没有,则会导致未定义行为,否则就是简单明了的内存泄漏

MyClass *myObject = new MyClass();

在堆上分配一个MyClass类型的对象,并将myObject指向动态分配的对象的地址。您仍然拥有指向该对象的指针,可以通过稍后调用delete来释放该指针。


如果您的问题是,如何最好地执行此操作,
答案是根本不使用动态分配的对象:

MyClass obj;

好文推荐:

为什么C++程序员应尽量减少使用'new'?


[参考 1:]
C++11 标准:3.8.4:

一个程序可以通过重复使用对象所占据的存储空间或显式调用具有非平凡析构函数的类类型对象的析构函数来结束任何对象的生命周期。对于具有非平凡析构函数的类类型对象,程序不需要在重复使用或释放对象所占据的存储空间之前显式地调用析构函数;但是,如果没有显式调用析构函数或者没有使用delete-expression(5.3.5)释放存储空间,则析构函数将不会被隐式调用,并且任何依赖于析构函数产生的副作用的程序都具有未定义行为。


5
为什么在析构函数中释放一个有副作用的堆分配对象会产生未定义行为? - Alex B
2
@AlexB:因为标准明确规定了。我为您添加了引用以供参考。此外,这是相当直观的行为,例如在析构函数中关闭文件句柄或描述符,如果该函数从未被调用,则会出现未定义行为。 - Alok Save
2
只有当程序依赖于析构函数的副作用时,它才是未定义行为,但这实际上只是一种重言。即使析构函数可能具有副作用,如果忽略它们,则泄漏内存仍然是泄漏内存。 - Lee Daniel Crocker
@Flexo:你提供的问题特别询问了内存泄漏是否会导致未定义行为,接受的答案在某种程度上是正确的。没有内存泄漏不会导致UB。而是在满足析构函数产生的副作用被程序进一步使用的条件下,没有调用new指针上的delete才会导致UB。也许这个答案需要编辑以详细说明这一点。 - Alok Save
1
@LeeDanielCrocker:我已经添加了标准中的确切引用来进行说明。即使我的措辞可能不够清晰,它也已经表述得足够明确了。 - Alok Save
显示剩余5条评论

24
第一个例子是:在堆栈上为 MyObject 的一个实例分配内存,然后在堆上为另一个实例分配内存,构造堆上的实例,将其内容复制到堆栈上的实例中,然后丢失堆指针的跟踪,因此无法释放。
第二个例子是:在堆栈上分配指针,为MyObject 的实例在堆上分配空间,构造它,并将指针分配给其地址,以便以后可以释放。
第二种情况使用的内存更少,速度更快,并且不会泄漏内存。第一种情况表明“我不理解C ++”。

5
第一点是无意义的。
MyClass myObject = *new MyClass();
< p > 在等号后面分配内存并创建新的 MyClass 对象。第一部分通过使用RHS < code > MyClass 对象调用复制构造函数创建一个新的 MyClass 对象。然后,由于您没有保存指向它的指针以进行删除操作,因此RHS中分配的内存泄漏。 < / p > < p > 上述语句与编写以下内容相同。 < / p >
MyClass myObject;

接下来

Leak memory equal to size of MyClass.

首先,决定您希望将对象放置在堆栈还是堆中。
如果您想要在堆栈上创建对象,则执行以下操作:
MyClass myObject;

这创建了一个MyClass对象 - 它适用于大多数情况。
如果您需要在堆上创建一个对象,则执行以下操作:
MyClass *myObject = new MyClass();

第一种方式 - 在堆栈上分配更有效。您进行堆分配是出于其他原因
  • 在编译时,您不知道需要创建多少对象。
  • 多态地使用类。

1
不是同一回事 - 复制构造函数至少需要可见,可能会被调用,而 MyClass myObject; 总是默认构造的。 - Flexo
我想编辑和更改“无意义”的内容(它可以编译,它会做一些事情,并且可能会有某个疯子设计一个系统,需要你像这样做一些事情,可能是一个网络人员),并将其更改为“无价的”,“喜剧黄金”,“白痴般的”和“爬行动物般的”。 - kfsone
1
我认为“胡说八道”这个词用得太强了,但我也不会说它很有趣(或类似的词)。它可能在“正确地”使用一个设计不佳的类,但通常情况下,它会泄露内存,并且并不是原本预期的结果。如果这是有意为之的,至少你也需要在那里放一个好的解释性注释。 - mwfearnley
只要我在程序后面使用 delete &myObject,那么使用 MyClass& myObject = *new MyClass(); 是可以的吗? - John Militer

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