【问题标题】:C++ delete an objectC++ 删除一个对象
【发布时间】:2012-01-08 18:57:39
【问题描述】:

我在处理 C++ 程序中的内存方面没有经验,所以我想在这种情况下给我一些建议:

我想在一个类的函数中创建一个new Object,这在程序结束之前是必不可少的。就我而言,如果我使用运算符new,我有时应该删除它。考虑到它必须在一个类中初始化,我何时以及如何最终删除它?

【问题讨论】:

    标签: c++ memory-management new-operator


    【解决方案1】:

    我建议智能指针习语

    #include <memory>
    
    struct X 
    {
         void foo() { }
    };
    
    std::share_ptr<X> makeX() // could also be a class member of course
    {
        return std::make_shared<X>();
    }
    
    int main()
    {
         std::share_ptr<X> stayaround = makeX();
    
         // can just be used like an ordinary pointer:
    
         stayaround->foo();
    
         // auto-deletes <sup>1</sup>
    }
    

    如果指针确实是一个静态变量,您可以替换为unique_ptr(其工作方式类似,但在赋值时传递所有权;这意味着指针不必保留引用计数)

    注意要了解有关 C++ 智能指针的更多信息,请参阅 smart pointers (boost) explained

    注意如果您没有 TR1/C++0x 对此的支持,您可以使用 Boost Smartpointer


    1 除非您泄露 shared_ptr 本身的副本;这将是一些以前看不见的智能指针的奇怪用法:)

    【讨论】:

    • 为什么默认使用std::shared_ptr?为什么不std::unique_ptr
    • @Nawaz:因为它更普遍适用。一方面,我假设代码由多个函数体组成,并且指针被传递。唯一的指针语义可能适用,但一般不适用。
    • @sehe:如果更普遍适用,那为什么std::unique_ptr会存在?
    • @Nawaz:你是在捉弄我吗 :) 看看我的回答...(I think you know the answer these questions yourself 瞬间 - 我说错了吗?)
    • @sehe:其实我见过很多人默认使用std::shared_ptr,很少看到std::unique_ptr,我觉得std::unique_ptr应该比std::shared_ptr更普遍使用。
    【解决方案2】:

    编辑:使用某种智能指针通常是个好主意,但我相信对 C++ 中的手动内存管理有一个扎实的理解仍然是必不可少的。

    如果您希望类中的对象一直持续到程序结束,您可以简单地将其设为成员变量。从您所说的来看,没有什么建议您需要在这里使用newdelete,只需将其设为自动变量即可。如果您确实想使用newdelete 进行练习,您应该阅读constructorsdestructors 的类(您可以并且将使用newdelete 在课外,但我试图保持与您的问题相关)。这是我之前准备的:

    class Foo
    {
        public:
            Foo();  // Default constructor.
            ~Foo(); // Destructor.
    
        private:
            int *member;
    }
    
    Foo::Foo() // Default constructor definition.
    {
        member = new int; // Creating a new int on the heap.
    }
    
    Foo::~Foo() // Destructor.
    {
        delete member; // Free up the memory that was allocated in the constructor.
    }
    

    这是一个简单的示例,但希望能对您有所帮助。请注意,只要对象还活着,变量就会持续存在。如果对象被销毁或超出范围,将调用析构函数并释放内存。

    【讨论】:

    • 这几乎就是我打算做的。不过我担心的是,如果对象在 main.js 中不是“可见的”,我应该何时调用析构函数。我应该创建一个函数将其传递给 main 然后删除吗?
    • 析构函数的美妙之处在于您不需要调用它。不仅如此,您不能调用它。当您的对象实例超出范围(例如程序结束)时,将调用对象的析构函数,删除由new 分配的内存。如果您要在堆上创建 Foo 的实例,例如Foo f = new Foo;,然后你必须在完成后致电delete f;。调用delete f; 会从堆中删除实例,但不会在调用f 的析构函数之前删除,这将删除member 整数使用的内存。
    • 如果成员的初始化发生在构造函数方法的另一个中,有什么改变吗?如果指针不为 NULL,我应该然后检查析构函数并删除它吗?
    • 归根结底,您的会员需要被初始化,然后再被删除(如果您想使用它:P)。只要您这样做,它是在构造函数中还是稍后(例如 setter 方法)中初始化都没有关系。是的,您应该在任何重要的应用程序中删除它之前检查指针!= 0。此外,每当您delete 一个指针时,您应该在之后将其设置为 0,这样您就不会意外引用已删除的内存。您不必担心在析构函数中将指针设置为 0,因为包含的对象正在被销毁。
    【解决方案3】:

    您可以按照 Sehe 的建议使用智能指针,也可以在函数中创建一个静态对象并返回对它的引用。您不需要显式删除对象,当进程终止时,对象将被删除。喜欢:

    struct X {};
    
    X& makeX() // could also be a class member of course
    {
        static X x;
        return x;
    }
    
    int main()
    {
         X& stayaround = makeX();
    }
    

    【讨论】:

      【解决方案4】:

      在大多数操作系统(尤其是 Linux)上,如果您使用 new Object 分配对象指针,并且不要打扰 delete-ing,因为您在程序结束之前都需要它,真的不会造成任何伤害.您的程序内部存在一些内存泄漏(您可以使用valgrind 来寻找此类泄漏),但内核将在进程结束时释放进程使用的所有内存。

      更好的选择是为应用程序数据设置一个单例类,例如QApplication 在 Qt 中,ahd 在您的 main 的早期构造该类中的单个实例,并让该类包含指向您的 Object 的智能或哑指针。析构函数应该delete 那个对象。

      【讨论】:

      • 我不推荐这种方法,因为在存在“已知”或“故意”泄漏的情况下很难发现任何真正内存泄漏跨度>
      • 另外,它降低了程序的可移植性。
      • 您也可以只创建该类的全局实例。没有必要对它进行单例化。
      • @R.MartinhoFernandes:您的意思是原始发帖人Object 的全局实例?他要动态分配!!
      • 不,我的意思是你想要创建单例的任何对象的全局实例。
      猜你喜欢
      • 1970-01-01
      • 2011-01-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多