在堆上分配指针的原因是什么?

What are the reasons to allocate a pointer on the heap?

可能这个问题已经有人问过,但我找不到。如果你看到了什么,请重定向我。 问题: 使用 :

有什么好处
myClass* pointer;

超过

myClass* pointer = new(myClass);

通过阅读其他主题,我了解到第一个选项在堆栈上分配一个 space 并使指针指向它,而第二个选项在堆上分配一个 space 并创建一个指针指向它。 但我还读到第二个选项很乏味,因为您必须使用 delete 解除分配 space。 那么为什么有人会使用第二种选择。 我有点菜鸟所以请详细解释。

编辑

#include <iostream>

using namespace std;

class Dog
{
        public:
                void bark()
                {
                        cout << "wouf!!!" << endl;
                }

};


int main()
{

        Dog* myDog = new(Dog);
        myDog->bark();
        delete myDog;
        return 0;

}

#include <iostream>

using namespace std;

class Dog
{
        public:
                void bark()
                {
                        cout << "wouf!!!" << endl;
                }

};


int main()
{

        Dog* myDog;
        myDog->bark();
        return 0;

}

都编译给我"wouf!!!"。那么我为什么要使用 "new" 关键字呢?

I understand that the first option allocates a space on the stack and makes the pointer point to it while the second allocates a space on the heap and make a pointer point to it.

上面是不正确的——第一个选项在堆栈上为指针本身分配space,但没有为任何分配space指针指向的对象。也就是说,指针没有指向任何特定的东西,因此没有用处(unless/until 你将指针设置为指向某物)

特别是,这段代码似乎“有效”纯粹是盲目的运气:

Dog* myDog;
myDog->bark();   // ERROR, calls a method on an invalid pointer!

... 上面的代码正在调用 未定义的行为 ,在理想情况下,它只会崩溃,因为您在无效指针上调用方法。但是 C++ 编译器通常更喜欢最大化效率而不是优雅地处理程序员错误,因此它们通常不会检查无效指针,并且由于您的 bark() 方法实际上不使用 [=14= 中的任何数据] 对象,它能够在没有任何明显崩溃的情况下执行。尝试将您的 bark() 方法设为虚拟方法,OTOH,您可能会看到上述代码发生崩溃。

the second allocates a space on the heap and make a pointer point to it.

没错。

But I read also that the second option is tedious because you have to deallocate the space with delete.

不仅乏味,而且容易出错 -- 很容易(在一个不平凡的程序中)以忘记调用 delete 的代码路径结束,然后发生内存泄漏。或者,您最终可能会在同一个指针上调用 delete 两次,然后您会出现未定义的行为,并且可能会崩溃或数据损坏。调试这两个错误都不是很有趣。

So why would one ever use the second option.

传统上,当您需要对象保持有效的时间超过调用代码的范围时,您会使用动态分配——例如,如果您需要对象在您创建对象的函数之后仍然存在在已经返回。将其与堆栈分配进行对比:

myClass someStackObject;

... 其中 someStackObject 保证在调用函数 returns 时被销毁,这通常是一件好事——但如果您需要 someStackObject 保留即使在您的函数返回后仍然存在。

如今,大多数人会完全避免使用 raw/C-style 指针,因为它们非常容易出错。在堆上分配对象的现代 C++ 方法如下所示:

std::shared_ptr<myClass> pointer = std::make_shared<myClass>();

... 这是首选,因为它为您提供了一个堆分配的 myClass 对象,只要至少有一个 std::shared_ptr 指向它(很好),但也将在没有 std::shared_ptr 指向它的那一刻自动删除(更好,因为这意味着没有内存泄漏并且不需要显式调用 delete,这意味着没有潜在的双删除)