代码之家  ›  专栏  ›  技术社区  ›  NTDLS

为什么我应该/不应该使用“new”操作符来实例化一个类,为什么?

  •  10
  • NTDLS  · 技术社区  · 17 年前

    超复杂 类别,例如:

    
    class CDoSomthing {
    
        public:
            CDoSomthing::CDoSomthing(char *sUserName, char *sPassword)
            {
                //Do somthing...
            }
    
            CDoSomthing::~CDoSomthing()
            {
                //Do somthing...
            }
    };
    

    如何在全局函数中声明本地实例?

    
    int main(void)
    {
        CDoSomthing *pDoSomthing = new CDoSomthing("UserName", "Password");
    
        //Do somthing...
    
        delete pDoSomthing;
    }
    

    --或--

    
    int main(void)
    {
        CDoSomthing DoSomthing("UserName", "Password");
    
        //Do somthing...
    
        return 0;
    }
    
    7 回复  |  直到 16 年前
        1
  •  27
  •   Mark Ransom    17 年前

    首选局部变量,除非需要对象的生存期扩展到当前块之外。(局部变量是第二个选项)。这比担心内存管理简单多了。

    SomeFunction(&DoSomthing);
    
        2
  •  22
  •   mghie    17 年前

    在堆栈上声明变量与在堆中声明变量时,有两个主要注意事项—生存期控制和资源管理。

    当您严格控制对象的生命周期时,在堆栈上进行分配非常有效。这意味着您不会将该对象的指针或引用传递给本地函数范围之外的代码。这意味着,没有输出参数,没有COM调用,没有新线程。有很多限制,但是在从当前作用域正常或异常退出时,您可以正确地清理对象(不过,您可能需要使用虚拟析构函数读取堆栈展开规则)。堆栈分配的最大缺点是:堆栈通常被限制为4K或8K,因此您可能需要小心放置在堆栈上的内容。

    另一方面,在堆上进行分配需要手动清理实例。这也意味着您可以自由地控制实例的生命周期。您需要在两种情况下执行此操作:a)将该对象传递到范围之外;或者b)对象太大,在堆栈上分配它可能会导致堆栈溢出。

    顺便说一句,这两者之间的一个很好的折衷办法是在堆上分配对象,并在堆栈上分配指向它的智能指针。这确保了您不会浪费宝贵的堆栈内存,同时仍能在范围退出时进行自动清理。

        3
  •  13
  •   R. Martinho Fernandes    17 年前

    第二种形式是所谓的RAII(资源获取是初始化)模式。与第一种方法相比,它有许多优点。

    使用时 new ,你必须使用 delete 您自己,并保证它将始终被删除,即使引发异常。你必须自己保证这一切。

    如果使用第二种形式,当变量超出范围时,它总是自动清除。如果抛出异常,堆栈将展开,并将其清理。

        4
  •  6
  •   Tim Cooper    14 年前

    除了到目前为止所说的,还需要考虑其他性能因素,特别是在内存分配密集型应用程序中:

    1. 使用 new 将从堆中分配内存。在密集(极其频繁)分配和解除分配的情况下,您将在以下方面付出高昂的代价:
      • 锁定:堆是进程中所有线程共享的资源。堆上的操作可能需要锁定堆管理器(在运行时库中为您完成),这可能会显著降低速度。
      • 碎片:堆碎片。您可能会看到malloc/new和free/delete返回的时间增加了10倍。这加剧了上述锁定问题,因为管理碎片堆需要更多时间,更多线程排队等待修复锁定。(在Windows上,您可以为堆管理器设置一个特殊标志,以便它试探性地尝试减少碎片。)

    new/malloc (一方面,您必须这样做,另一方面,这些对象通常寿命足够长,因此与堆管理器相比,您基本上只需支付0成本。)

        5
  •  3
  •   Paul Beckingham    17 年前

        6
  •  2
  •   user68158 user68158    17 年前

    两者之间最大的区别在于,新对象启动指向该对象的指针。

    通过创建对象而不创建新对象,启动的对象存储在堆栈上。如果它是用new启动的,它将返回一个指针,指向在堆上创建的新对象。它实际上返回一个指向新对象的内存地址。发生这种情况时,需要对变量进行内存管理。使用完该变量后,需要对其调用delete以避免内存泄漏。如果没有新的运算符,当变量超出范围时,内存将自动释放。

        7
  •  0
  •   arul    17 年前

    Mark Ransom是正确的,您还需要使用 new

    推荐文章