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

roi*_*mon -1 c++ pointers class dynamic-memory-allocation static-memory-allocation

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

myClass* pointer;
Run Code Online (Sandbox Code Playgroud)

超过

myClass* pointer = new(myClass);
Run Code Online (Sandbox Code Playgroud)

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

编辑

#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;

}
Run Code Online (Sandbox Code Playgroud)

#include <iostream>

using namespace std;

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

};


int main()
{

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

}
Run Code Online (Sandbox Code Playgroud)

两者都编译并给我“wouf!!!”。那么为什么我应该使用“new”关键字呢?

Jer*_*ner 6

我知道第一个选项在堆栈上分配一个空间并使指针指向它,而第二个选项在堆上分配一个空间并使指针指向它。

上面是不正确的——第一个选项在堆栈上为指针本身分配空间,但没有为指针指向的任何对象分配空间。也就是说,指针没有指向任何特定的东西,因此使用起来没有用处(除非/直到您将指针设置为指向某个东西)

特别是,这段代码看起来“有效”只是纯粹的盲目运气:

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

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

第二个在堆上分配一个空间并让一个指针指向它。

那是对的。

但我还读到,第二个选项很乏味,因为您必须通过删除来释放空间。

不仅乏味,而且容易出错——很容易(在一个不平凡的程序中)最终得到一个忘记调用delete的代码路径,然后就会出现内存泄漏。或者,您最终可能会对同一指针调用两次删除,然后出现未定义的行为,并且可能会崩溃或数据损坏。调试这两个错误都没有多大乐趣。

那么为什么人们会使用第二种选择呢?

传统上,当您需要对象保持有效的时间超过调用代码的范围时,您会使用动态分配 - 例如,如果您需要即使在创建对象的函数返回后,对象也能保留下来。与堆栈分配进行对比:

myClass someStackObject;
Run Code Online (Sandbox Code Playgroud)

...其中someStackObject保证在调用函数返回时被销毁,这通常是一件好事 - 但如果someStackObject即使在函数返回后您也需要保持存在,则情况并非如此。

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

std::shared_ptr<myClass> pointer = std::make_shared<myClass>();
Run Code Online (Sandbox Code Playgroud)

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