C++删除一个对象

5

我对在C++程序中处理内存方面没有经验,因此我希望在这种情况下得到一些建议:

我想在类的一个函数中创建一个new Object,这个对象在整个程序中都是必需的。据我所知,如果我使用new运算符,有时候需要删除它。考虑到它必须在类中初始化,那么什么时候以及如何最终删除它呢?

4个回答

5

我建议使用智能指针技巧

#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++智能指针的信息,请参见解释Boost智能指针 如果您没有对此进行TR1 / C ++ 0x支持,您可以使用Boost Smartpointer。 除非您正在泄漏 shared_ptr本身的副本; 这将是以前从未见过的智能指针的奇怪用法 :)

1
你为什么默认使用 std::shared_ptr?为什么不用 std::unique_ptr - Nawaz
@sehe:如果它适用于更普遍的情况,那么为什么还需要std::unique_ptr呢? - Nawaz
@Nawaz:你在逗我吗 :) 看看我的回答...(我认为你可以很快地知道这些问题的答案 - 我说错了什么吗?) - sehe
@sehe:实际上,我看到很多人默认使用std::shared_ptr,很少看到std::unique_ptr,但我认为std::unique_ptr应该比std::shared_ptr更普遍地使用。 - Nawaz
这里的问题很简单,是语义学上的一个问题。在口语化的英语中,“一般地(generally)”意味着“有点儿用”并暗示着“更经常”或者“更广泛”。在数学英语中,“一般地(general)”则意味着可以适用于比你所比较的事物更多的情况。真是个愚蠢的相反意思 :) - McBeth
显示剩余7条评论

2

您可以像Sehe建议的那样使用智能指针,也可以在函数中创建一个静态对象并返回对其的引用。在进程终止时,无需显式删除该对象,该对象将被删除。例如:

struct X {};

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

int main()
{
     X& stayaround = makeX();
}

2
编辑:使用某种智能指针通常是一个好主意,但我认为在C++中仍然需要对手动内存管理有扎实的理解。
如果你想让一个类中的对象持续到程序结束,你可以将它作为成员变量。从你所说的内容来看,没有任何迹象表明你需要在这里使用newdelete,只需将其作为自动变量即可。如果你想练习使用newdelete,你应该阅读关于类的构造函数析构函数(你可以在类外部使用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.
}

这是一个简单的例子,但它会帮助您更好地理解。请注意,只有在对象存在期间,变量才会持久存在。如果对象被销毁或超出作用域,则将调用析构函数并释放内存。


这几乎是我想做的。但让我担心的是,如果对象在主函数中不“可见”,我应该何时调用析构函数。我应该制作一个函数在主函数中传递它然后删除吗? - arjacsoh
2
析构函数的美妙之处在于您不需要调用它。不仅如此,您不能调用它。当对象实例超出范围(例如程序结束)时,将调用对象的析构函数,该函数会删除由new分配的内存。如果您要在堆上创建Foo的实例,例如Foo f = new Foo;,则在完成后必须调用delete f;。调用delete f;会从堆中删除实例,但在调用f的析构函数之前,该函数将删除member整数使用的内存。 - Chris Parton
如果成员的初始化发生在构造方法之外,会有什么变化吗?那我是否应该在析构函数中检查指针是否不为NULL,然后再删除它呢? - arjacsoh
在一天的最后,你的成员需要被初始化,然后稍后删除(如果你想使用它 :P)。不管是在构造函数中还是稍后在其他地方(例如setter方法)初始化都没关系,只要你这样做了。 是的,在任何非平凡的应用程序中删除指针之前,应该检查指针是否等于0。此外,每当你delete一个指针时,应该将其设置为0,以便你不会意外引用已删除的内存。你不必太担心在析构函数中将指针设置为0,因为包含对象正在被销毁。 - Chris Parton

0

在大多数操作系统(特别是Linux)上,如果你使用new Object分配一个对象指针,并且不打算delete它,因为你需要它直到程序结束,那么实际上并没有什么伤害。你的程序中会有一些内存泄漏(你可以使用valgrind来查找这样的泄漏),但是内核将在进程结束时释放该进程使用的所有内存。

更好的选择是为应用程序数据创建一个单例类,例如Qt中的QApplication,并在main函数中早期构建一个单例实例,并让该类包含对Object的智能或者普通指针。析构函数应该delete该对象。


5
我不建议采用这种方式,因为在存在“已知”的或“故意”的泄漏情况下,会使真正的内存泄漏问题难以被发现。 - sehe
此外,它会使程序的可移植性降低。 - Tamás Szelei
你也可以创建该类的全局实例。没有必要将其作为单例。 - R. Martinho Fernandes
@R.MartinhoFernandes: 你的意思是创建原始发布者“Object”的全局实例吗?他想要动态分配它!! - Basile Starynkevitch
不,我指的是您想要创建单例模式的任何对象的全局实例。 - R. Martinho Fernandes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接