-2

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

myClass* pointer;

超过

myClass* pointer = new(myClass);

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

编辑

#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”关键字呢?

4

1 回答 1

4

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

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

特别是,这段代码似乎完全“工作”只是纯粹的盲目运气:

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

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

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

那是对的。

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

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

那么为什么要使用第二种选择。

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

myClass someStackObject;

...someStackObject当调用函数返回时,它保证会被销毁,这通常是一件好事——但如果你需要someStackObject在函数返回后一直存在,那就不行了。

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

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

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

于 2018-02-07T22:30:26.093 回答