【问题标题】:What is difference between instantiating an object using new vs. without使用 new 实例化对象与不实例化对象有什么区别
【发布时间】:2011-04-10 02:16:38
【问题描述】:

在 C++ 中,

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

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) ctor。我也意识到在第二种情况下 t 需要被删除,因为它是在堆上分配的。还有其他区别吗?

【问题讨论】:

  • 它并不能真正算作一个答案,但除了已经给出的答案之外,您可能有兴趣知道,如果您想编写自己的内存管理,您可以覆盖 operator new/delete(为了更好性能)。

标签: c++ constructor new-operator


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    行:

    Time t (12, 0, 0);
    

    ...在本地范围内分配Time类型的变量,一般在堆栈上,当其范围结束时将被销毁。

    相比之下:

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

    ... 通过调用::operator new()Time::operator new() 分配内存块,然后调用Time::Time() 并将this 设置为该内存块内的地址(并且也作为@987654328 的结果返回@),然后存储在t中。如您所知,这是通常在堆上完成的(默认情况下),并要求您稍后在程序中delete 它,而t 中的指针通常 > 存储在堆栈中。

    注意:我在这里的一般用法是指通用实现。 C++ 标准不区分堆栈和堆作为机器的一部分,而是根据它们的生命周期来区分。本地范围内的变量被称为“自动存储持续时间”,因此在本地范围结束时被销毁;并且使用new 创建的对象被称为具有“动态存储持续时间”,并且仅在deleted 时被销毁。实际上,这意味着在堆栈上创建和销毁自动变量,而在堆上存储动态对象,但这不是语言所要求的。

    【讨论】:

    • "该内存块中的地址" -- 只是块中任何位置的任何地址或特定位置(例如开头)?
    • @Sev:一般接近开头。对于 POD 类,它将位于或非常接近开头,对于具有虚拟成员和/或继承的类,指针通常会在块内更远,以便为 vtable 和继承的成员(如果有)腾出空间。
    • @greyfade:在第二行代码中,t 是一个指向 Time 的指针,我意识到 t 指向一个 Time 类型的对象,该对象分配在堆上,但 t 本身分配在栈还是堆?
    • @Calpis: t 是在本地范围内声明的“自动变量”。所以是的,它通常分配在堆栈上。但它通常与讨论无关,因为它只是指向 Time 对象。
    • @greyfade:实际上,它相关的,很高兴看到有人问这个问题。人们忘记了指向对象的指针本身就是对象,它们也值得我们关注!
    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

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

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

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

      【讨论】:

        【解决方案5】:

        No..没有其他区别..

        【讨论】:

          【解决方案6】:

          与您已经知道的没有其他区别。

          假设您的代码正在使用默认 operator new 的服务。

          【讨论】:

            【解决方案7】:

            一个更明显的区别是在访问 t 的变量和方法时。

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

            【讨论】:

              【解决方案8】:
              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;) 的声明。
              【解决方案9】:
              • 使用新的: 调用operator new函数获取动态内存,然后调用constructor函数。
              • 不使用新的: 不会调用operator new函数,直接调用constructor函数。栈会直接使用,malloc没用。

              【讨论】:

                猜你喜欢
                • 2011-02-22
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2013-02-11
                • 1970-01-01
                • 2017-05-13
                • 2012-01-19
                相关资源
                最近更新 更多