C++;对象实例化 我是一个C程序员,试图理解C++。许多教程使用以下代码段演示对象实例化: Dog* sparky = new Dog();

C++;对象实例化 我是一个C程序员,试图理解C++。许多教程使用以下代码段演示对象实例化: Dog* sparky = new Dog();,c++,instantiation,C++,Instantiation,这意味着稍后您将执行以下操作: delete sparky; 这是有道理的。现在,在不需要动态内存分配的情况下,是否有任何理由使用上述方法而不是 Dog sparky; 一旦sparky超出范围,就调用析构函数 谢谢 好吧,使用指针的原因与在C中使用分配给malloc的指针的原因完全相同:如果你想让你的对象比你的变量活得长 如果可以避免,甚至强烈建议不要使用新操作符。特别是如果您使用异常。一般来说,让编译器释放对象更安全。我担心的唯一原因是Dog现在分配在堆栈上,而不是堆上。所以如果狗的大小

这意味着稍后您将执行以下操作:

delete sparky;
这是有道理的。现在,在不需要动态内存分配的情况下,是否有任何理由使用上述方法而不是

Dog sparky;
一旦sparky超出范围,就调用析构函数


谢谢

好吧,使用指针的原因与在C中使用分配给malloc的指针的原因完全相同:如果你想让你的对象比你的变量活得长


如果可以避免,甚至强烈建议不要使用新操作符。特别是如果您使用异常。一般来说,让编译器释放对象更安全。

我担心的唯一原因是Dog现在分配在堆栈上,而不是堆上。所以如果狗的大小是兆字节,你可能会有问题

如果您确实需要选择新建/删除路线,请注意例外情况。因此,您应该使用auto_ptr或boost智能指针类型之一来管理对象生命周期

当您可以在堆栈上进行分配时,没有理由新建(在堆上)(除非出于某种原因,您有一个小堆栈并希望使用堆)


您可能想考虑使用SydDypTR(或者它的变体之一)如果您确实希望在堆上进行分配,则可以从标准库中删除。一旦对共享\u ptr的所有引用都不存在,就可以为您执行删除操作。

相反,您应该始终选择堆栈分配,根据经验,您的用户代码中不应该有new/delete

正如您所说,当在堆栈上声明变量时,它的析构函数在超出范围时自动调用,这是跟踪资源生存期和避免泄漏的主要工具

一般来说,每次需要分配资源时,无论是内存(通过调用new),文件句柄、套接字或其他任何内容,将其包装在一个类中,在该类中构造函数获取资源,析构函数释放它。然后,您可以在堆栈上创建该类型的对象,并且可以保证资源在超出范围时被释放。这样,您就不必到处跟踪新/删除对以确保您可以避免内存泄漏

这个成语最常见的名字是

此外,还可以研究智能指针类,当您必须在专用RAII对象之外分配新对象时,这些类用于包装生成的指针。您可以将指针传递给智能指针,智能指针随后跟踪其生存期,例如通过引用计数,并在最后一次引用时调用析构函数超出范围。标准库具有用于基于范围的简单管理的
std::unique_ptr
,以及执行引用计数以实现共享所有权的
std::shared_ptr

许多教程演示了对象 使用诸如

所以你发现大多数教程都很烂
大多数教程教你糟糕的C++实践,包括调用NeX/DELL来创建变量,当不需要时,给你一个很难跟踪你分配的生命周期。

< P>把堆作为一个非常重要的不动产,并非常明智地使用它。基本的经验法则是尽可能使用堆栈并在没有其他方法时使用堆。通过在堆栈上分配对象,您可以获得许多好处,例如:

(1) 。您不必担心异常情况下的堆栈展开


(2) 。您不必担心由于分配的空间超过堆管理器所需的空间而导致的内存碎片。

我从不太了解运算符地址的人那里看到过这种反模式。如果他们需要用指针调用函数,他们总是在堆上进行分配,以获得指针

void FeedTheDog(Dog* hungryDog);

Dog* badDog = new Dog;
FeedTheDog(badDog);
delete badDog;

Dog goodDog;
FeedTheDog(&goodDog);

我在VisualStudio中也遇到了同样的问题。您必须使用:

yourClass->classMethod()

而不是:


classMethod()

还有一个其他人没有提到的原因,就是为什么您可以选择动态创建对象。动态的、基于堆的对象允许您利用。

尽管在堆栈上有东西在分配和自动释放方面可能是一个优势,但它也有一些缺点

  • 您可能不希望在堆栈上分配大型对象

  • 动态调度!考虑这个代码:

  • #包括
    甲级{
    公众:
    虚空f();
    虚拟~A(){}
    };
    B类:公共A{
    公众:
    虚空f();
    };
    
    void A::f(){cout原始指针在需要类似于auto_ptr的语义(转移所有权)时非常有用,但保留非抛出交换操作,不需要引用计数的开销。边缘大小写可能,但很有用。这是一个正确的答案,但我永远不会养成在堆栈上创建对象的习惯,因为它永远不会完全清楚该对象将有多大。你只是要求堆栈溢出例外格雷戈:当然可以。但是,正如你所说的,一个边缘情况。最好是指针避免。但是,在语言中有一个原因,不可否认。):如果对象很大,就把它包在一个RAII对象中,这个对象可以分配到堆栈上,并包含堆分配数据的指针。@不,我不是。C++编译器不需要。对象膨胀。通常情况下,最糟糕的情况是它会被四舍五入到四个字节的最接近倍数。通常,包含指针的类占用的空间与指针本身一样大,因此它在堆栈使用方面不会花费任何成本。这并不能回答问题。您需要注意的是,必须使用不同的语法才能访问分配的对象在堆上(通过指向对象的指针)和在堆栈上分配的对象