清理堆分配对象的良好实践或约定

Good practice or convention for cleanup heap allocated object?

本文关键字:约定 分配 对象      更新时间:2023-10-16

我正在学习c++。我有C, c#, ObjC的背景。相当高级的语言。

在c#或ObjC上,作为函数或方法的结果返回堆分配的对象是微不足道的。因为对象的清理是(按约定)管理的。它将在适当的时候被销毁。

但是我不知道如何在c++中处理这个问题。

例如

std::string* makeString()
{
    std::string* str = GetSomeStringFromArbitrarySource ();
    SaveSomewhereElseInternally (str);
    return str;
}
void useString ()
{
    std::string* str = makeString ();
    // Where and how should I cleanup the `str` object?
    // It is not safe `delete str` here because it may be used on another place.
}

当堆分配的对象传递给许多函数时,推荐和传统的清理方法是什么?

我看了几个智能指针,但它们看起来并不真正减少复杂性或关心的事情。我是不是误解了智能指针?

我看了几个智能指针,但它们看起来并没有真正减少复杂性或关心的事情。我是不是误解了智能指针?

很可能,是的。在c++中,因为你必须自己处理这个问题(没有GC会帮你清理),所以你需要一种方法来跟踪每个对象的使用情况。

您可以手动将每个newdelete匹配,但这有时是困难的或不可能的,例如在上面的场景中。没有办法知道对象是否在其他地方被使用。

智能指针通过为你管理生命周期来解决这个问题,所以你不需要删除。它们使用各种机制来跟踪对象被使用的位置,并在最后一个完成时调用delete

话虽这么说,在这种特殊情况下根本没有太多理由使用指针。如果您正在使用std::string,您可以通过值传递字符串,这将永远不会是一个问题。

你误解了智能指针很可能和你写的原因一样:

std::string* makeString()

而不是大多数c++程序员会写的:

std::string makeString()

你需要更好地理解c++中的对象生命周期,然后智能指针的概念就会容易得多。

您需要为您的对象找出所需的生命周期,然后使用类型系统来强制该生命周期。

从你的例子中,当你想要销毁对象时,它一点也不清楚。

在c++中,对象按值传递是很常见的(就像Java/c#/等中的基本类型一样),所以除非你需要在不同的代码段之间共享std::string,否则通常的做法是按值返回字符串(将makeString写成std::string makeString())。

如果你确实需要在多个地方引用同一个对象,你应该仔细考虑设计,并决定程序的哪个部分可以安全地控制对象的生命周期。在该位置按值创建对象,然后在其他位置传递指针和引用。

你可能误解了智能指针。在c++中,另一种选择是程序员需要跟踪动态分配对象的生命周期和使用情况。这会影响软件的设计,也会导致人为错误的出现。当您使用智能指针时,对象的生命周期基本上已经为您考虑好了。

我是在经典的c++风格中长大的(没有智能指针),所以如果需要的话,我可以这样编程,但如果你是从c++开始的,那么智能指针真的是必须的。

如果可以使用c++ 11使用共享指针。这些指针实现了一种机制,一旦它们中的最后一个被销毁,就删除分配的对象。如果您正在使用c++ 03,请使用boost的共享指针。如果两者都不能使用,请尝试将堆分配包装在您在堆栈上分配的类中,然后将引用传递给周围的类,并读取RAII wiki。