使用new关键字实例化对象和不使用new关键字实例化对象有什么区别?

114

除了动态内存分配之外,以下两行代码之间是否有功能上的区别:

Time t (12, 0, 0); //t is a Time object

Time* t = new Time(12, 0, 0);//t is a pointer to a dynamically allocated Time object

我假设已经定义了一个Time(int, int, int)构造函数。我也意识到在第二种情况下,t需要被删除,因为它是在堆上分配的。还有其他区别吗?


10
除了已经给出的答案之外,以下内容算不上一个答案,但你可能会感兴趣的是,如果你想编写自己的内存管理(以获得更好的性能),你可以覆盖操作符new/delete。 - user180326
9个回答

138

这行代码:

Time t (12, 0, 0);

该代码在本地作用域中分配了一个Time类型的变量,通常在堆栈上,它的作用域结束时将被销毁。

相比之下:

Time* t = new Time(12, 0, 0);

通过调用::operator new()Time::operator new()来分配一块内存,然后使用该内存块中地址(也作为new的结果返回)设置this,调用Time::Time()构造函数,将其存储在t中。通常情况下,这是在堆上完成(默认情况下),并需要在程序中稍后使用delete进行删除,而t中的指针通常存储在栈上。

注意:我的“通常”是指常见实现方式。C++标准不将栈和堆区别为机器的一部分,而是以它们的生存期为依据。局部范围内的变量被称为“自动存储期”,因此在局部范围结束时被销毁;使用new创建的对象被称为“动态存储期”,仅在delete后才会被销毁。从实际角度来看,这意味着自动变量在栈上创建和销毁,而动态对象存储在堆上,但这不是语言要求的。


2
@Sev:通常靠近开头。对于POD类,它将在开头或非常接近开头,而对于具有虚成员和/或继承的类,指针通常会更深入块中,以腾出空间放置vtable和继承成员(如果有)。 - greyfade
2
@greyfade:在代码的第二行中,t是指向Time类型对象的指针,我意识到t指向在堆上分配的Time对象,但t本身是在堆上还是栈上分配的? - masotann
2
@Calpis:t是在本地范围内声明的“自动变量”。因此,它通常分配在堆栈上。但通常与讨论无关,因为它仅仅是指向Time对象。 - greyfade
1
@greyfade:实际上,这很相关,看到有人询问这个问题很好。人们常常忘记指向对象的指针本身也是对象,它们也值得我们关注! - Lightness Races in Orbit
@ greyfade 这两个变量都是在堆上创建的吗?还是 Time t (12, 0, 0); 在栈上创建的?我看了一个类似的问题,评论里有一些讨论(这里这里和其余的评论线程),但我不明白他的意思。你能澄清一下吗? - yadav_vi
显示剩余3条评论

36
另一个明显的区别是访问t的变量和方法时。
Time t (12, 0, 0);
t.GetTime();

Time* t = new Time(12, 0, 0);
t->GetTime();

5

就构造函数而言,这两种形式在功能上是相同的:它们只会导致构造函数在新分配的对象实例上被调用。你似乎已经对分配模式和对象生命周期的差异有了很好的掌握。


4

我认为你已经了解所有的差异。假设你已经很清楚通过指针和变量访问t成员的语法差异(好吧,指针也是一个变量,但我想你知道我的意思)。并且假设你知道在将t传递给函数时按值调用和按引用调用的区别。我相信你也明白如果你将t赋值给另一个变量,并通过那个其他变量进行更改会发生什么。结果将取决于t是否为指针。


3
  • 使用new:
  • 调用operator new函数获取动态内存,然后调用构造函数。

  • 不使用new:
  • 不会调用operator new函数,直接调用构造函数。将直接使用栈,不需要使用malloc。


2

与你已知的没有其他区别。

假设你的代码使用默认的operator new服务。


2

在堆上分配对象和在栈上分配对象之间在功能上没有区别。两者都会调用对象的构造函数。

顺便提一下,我建议你在堆上分配时使用boost的shared_ptr或scoped_ptr,它们在功能上也是等效的(scoped_ptr还有额外的实用性,可以限制您复制不可复制的指针):

scoped_ptr<Time> t(new Time(12, 0, 0));

1

没有.. 没有其他的区别..


-2
void foo (Time t)
{
  t = Time(12, 0, 0);
}

void bar (Time* t)
{
  t = new Time(12, 0, 0);
}


int main(int argc, char *argv[])
{
  Time t;
  foo(t);//t is not (12,0,0),its value depends on your defined type Time's default constructor. 

  bar(&t);//t is (12,0,0)
  return 0;
}

我认为你的注释"//t不是(12,0,0),它的值取决于你定义的类型Time的默认构造函数。"适用于它上面的那一行,即对象t(Time t;)的声明。 - AamodG

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