我听说越来越多,我应该使用智能指针而不是裸指针,尽管我已经实现了有效的内存泄漏系统。
使用智能指针的正确的编程方法是什么?它们是否真的应用,即使我检查分配的内存块上的内存泄漏?还是由我决定吗?如果我不使用它们,这可以被视为编程弱点吗?
如果强烈建议使用智能指针(例如:std :: auto_ptr),我应该使用而不是每个裸指针吗?
答案 0 :(得分:22)
您应该使用RAII来处理所有资源分配。
智能指针只是该规则的一个常见特例。
智能指针不仅仅是shared_ptr
。有不同的智能指针具有不同的所有权语义。使用适合您需求的那个。 (主要的是scoped_ptr
,shared_ptr
,weak_ptr
和auto_ptr
/ unique_ptr
(更喜欢后者)。根据您的编译器,它们可能是作为TR1的一部分在标准库中提供,或者根本不提供,在这种情况下,您可以通过Boost库获取它们。
是的,你绝对应该使用这些。它没有任何成本(如果正确完成,你会失去零性能),并且它会获得很多(内存和其他资源会自动释放,您不必记住手动处理它,并且使用资源获取代码)更短更简洁)
请注意,并非每个指针用法都代表某种资源所有权,因此并非所有原始指针使用都是错误的。如果您只需要指向其他人拥有的对象,则原始指针非常适合。但是如果你拥有该对象,那么你应该对它进行适当的所有权,或者通过赋予类本身的RAII语义,或者将它包装在一个智能指针中。
答案 1 :(得分:10)
你不能盲目地用std::auto_ptr
代替每个原始指针。特别是,auto_ptr
转让所有权转让,这对某些目的很有用,但绝对不适合其他目的。
有一个真正的原因有几种智能指针(例如,shared_ptr,weak_ptr,auto_ptr / unique_ptr等)每个都满足不同的目的。 “原始”指针的一个主要缺点是它具有如此多的不同用途(并且具有这种多功能性,主要是因为它在任何一个目的上很少或没有任何帮助)。智能指针往往更专业,这意味着他们可以更好地做一件事情,但也意味着你必须选择正确的工作,否则它将完全归咎于错误的事情。
答案 2 :(得分:4)
如果我确实使用它们,即使我检查分配的内存块上的内存泄漏了吗?
<强> YES 强>
智能指针的全部目的是,它可以帮助您实现 RAII(SBRM) ,这基本上让资源本身承担其释放的责任,资源不会必须明确依赖您 记住 才能解除分配。
如果我不使用它们,这可以被视为编程弱点吗?
<强> NO, 强>
如果您不使用智能指针(RAII),那么自行明确管理资源不是一个弱点,而是一个不方便或不必要的麻烦。实现RAII的智能指针的目的是提供有效且无障碍的资源处理方式,如果您不使用它,就不会使用它。强烈建议将其纯粹用于它提供的numerous advantages。
如果强烈建议智能指针 (例如:std :: auto_ptr) ,我应该使用它们而不是每个裸指针吗? / em>
<强> YES 强>
你应该尽可能使用智能指针,因为使用它们没有任何缺点,只是使用它们有很多好处
不要使用auto_ptr
,因为它已被弃用!!根据要求,您可以使用各种其他智能指针。您可以参考上面的链接以了解更多相关信息。
答案 3 :(得分:4)
智能指针允许自动定义它所引用的对象的生命周期。这是要理解的主要内容。
所以,不,你不应该在任何地方使用智能指针,只有当你想要自动化你的对象的生命周期而不是例如从出生时管理这些对象的对象致死它就像任何工具:它解决了特定类型的问题,而不是所有问题。
对于每个对象,您应该考虑它将经历的生命周期,然后选择一个最简单正确和有效的解决方案。有时它将是shared_ptr,因为您希望对象被多个组件使用,并且一旦不再使用就会被自动销毁。有时您只需要当前作用域/父对象中的对象,因此scoped_ptr可能更合适。有时您只需要一个实例的所有者,因此unique_ptr是合适的。也许你会发现你知道一个可能定义/自动化对象生命周期的算法的情况,所以你要为它编写自己的智能指针。
例如相反的情况,使用pool禁止使用smart_ptr。在这个特定的(但在嵌入式软件中很常见)案例中,裸指针可能是一个更受欢迎的简单而有效的解决方案。
有关更多解释,请参阅此答案(来自我):https://softwareengineering.stackexchange.com/questions/57581/in-c-is-it-a-reflection-of-poor-software-design-if-objects-are-deleted-manuall/57611#57611
答案 4 :(得分:4)
如果强烈建议使用智能指针(例如:std :: auto_ptr),我应该使用它们而不是每个裸指针吗?
在我看来,是的,你应该为你拥有的每个指针做它。
以下是我对C ++资源管理的看法(随意不同意):
这导致以下做法:
使boost::scoped_ptr
成为本地和成员变量的默认选择。请记住,对成员变量使用scoped_ptr
将使您的类不可复制。如果您不希望这样,请参阅下一点。
对容器使用boost::shared_ptr
或启用共享所有权:
// Container of MyClass* pointers:
typedef boost::shared_ptr<MyClass> MyClassPtr;
std::vector<MyClassPtr> vec;
std::auto_ptr
(C ++ 03)可用于所有权转移。例如,作为工厂或克隆方法的返回值:
// Factory method returns auto_ptr
std::auto_ptr<Button> button = Button::Create(...);
// Clone method returns auto_ptr
std::auto_ptr<MyClass> copy = obj->clone();
// Use release() to transfer the ownership to a scoped_ptr or shared_ptr
boost::scoped_ptr<MyClass> copy(obj->clone().release());
如果您需要存储一个您不拥有的指针,那么您可以使用原始指针:
this->parent = inParentObject;
在某些情况下,需要boost::weak_pointer
。有关详细信息,请参阅documentation。
答案 5 :(得分:4)
这是一个棘手的问题,而且目前有一种模式 在任何地方使用智能指针都不会让事情变得更容易。聪明 指针可以在某些情况下帮助,但你当然不能只是 无处不在地使用它们。有许多不同的类型 智能指针,你必须考虑哪一个是合适的 在每种情况下;甚至在那时,你的大部分指针(至少在典型的情况下) 我工作过的域中的应用程序应该是原始指针。
无论采用何种方法,都值得一提:
除非必须,否则请勿使用动态分配。在很多 应用程序,仅需要动态分配的东西 具有特定寿命的对象,由应用程序确定 逻辑。不要对具有值语义的对象使用动态分配。
关于实体对象,那些在其中建模的东西 应用程序域:这些应该根据创建和销毁 到程序逻辑。无论是否有指针 他们与否。如果他们的破坏导致问题,那么你有一个 你的程序逻辑错误(不正确处理事件, 等),使用智能指针不会改变任何东西。
实体对象的典型示例可能是a中的客户端连接
服务器,是在客户端连接时创建的,并在被破坏时创建
客户端断开连接。在许多这样的情况下,最合适的管理
将是delete this
,因为它是将接收的连接
断开事件。 (包含指向此类对象的指针的对象
必须注册,以便了解它
破坏。但是这样的指针纯粹是用于导航,而不应该
是聪明的指针。)
当人们尝试使用智能指针时,您通常会发现什么
无处不在 内存泄漏;典型的参考计数器没有
处理周期,当然,典型的应用程序充满了周期:a
Connection
将指向与其相关联的Client
,并且
Client
将包含已连接的Connection
列表。
如果智能指针是boost::shared_ptr
,那么也是明确的
悬挂指针的风险:创建两个指针很容易
boost::shared_ptr
到同一地址(导致两个计数器)
参考)。
答案 6 :(得分:2)
是。假设您可以使用C ++ 0x,请使用unique_ptr
或shared_ptr
(根据需要)将所有原始指针包装起来new
。在make_shared
的帮助下,shared_ptr
具有很高的效率。如果您不需要引用计数,那么unique_ptr
将为您提供更好的性能。它们都在集合和auto_ptr
是一个哑指针的其他情况下表现正常。
答案 7 :(得分:2)
一般情况下,您应该更喜欢智能指针,但也有一些例外。
如果您需要重新设置指针,例如提供const
版本,那么使用智能指针几乎不可能。
智能指针用于控制对象的生命周期。通常当您将指针传递给函数时,该函数不会影响生命周期;该函数不会尝试删除该对象,也不会存储指针的副本。在函数返回之前,调用代码无法删除对象。在这种情况下,哑指针是完全可以接受的。
答案 8 :(得分:0)
使用智能指针(shared_ptr或其他)无处不在是一个坏主意。最好使用shared_ptr来管理对象/资源的生命周期,但将它们作为参数传递给函数等并不是一个好主意。这增加了循环引用和其他极难跟踪错误的可能性(个人经验:尝试搞清楚谁如果每个函数调用都改变了引用计数,那么不应该持有200万行代码中的资源 - 你最终会认为做这类事情的人都是m *** ns。最好传递原始指针或引用。 与惰性实例化结合使用时情况更糟。 我建议开发人员应该知道他们编写的对象的生命周期,并使用shared_ptr来控制它(RAII),但不要扩展shared_ptr的使用范围。