使用智能指针作为编程标准?
我越来越多地听到,我应该使用智能指针而不是裸指针,尽管我已经实现了有效的内存泄漏系统。
使用智能指针的正确编程方法是什么?即使我检查分配的内存块上的内存泄漏,是否真的应该使用它们?还得由我来决定吗?如果我不使用它们,这是否可以被视为编程弱点?
如果强烈推荐使用智能指针(例如:std::auto_ptr),我应该使用它们而不是每个裸指针吗?
More and more I hear, that I should use smart pointers instead of naked pointers, despite I have effective memory leak system implemented.
What is the correct programming approach on using smart pointers please? Should they really be used, even if I check memory leaks on allocated memory blocks? Is it still up to me? If I do not use them, can this be considered as programming weakness?
If the smart pointers(ex: std::auto_ptr) are strongly recommended, should I use them instead of every naked pointer?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
您应该使用 RAII 来处理所有资源分配。
智能指针只是该规则的一个常见特例。
智能指针不仅仅是
shared_ptr
。不同的智能指针具有不同的所有权语义。使用适合您需要的一种。 (主要有scoped_ptr
、shared_ptr
、weak_ptr
和auto_ptr
/unique_ptr
(更喜欢后者(如果可用)。根据您的编译器,它们可能作为 TR1 的一部分在标准库中提供,或者根本不提供,在这种情况下您可以通过 Boost 库获取它们,是的,您绝对应该使用它们 。这些不会花费你任何成本(如果做得正确,你的性能损失为零),而且它会给你带来很多(内存和其他资源会自动释放,你不必记住手动处理它,并且你的代码使用了。资源变得更短、更简洁)
请注意,并非每个指针的使用都代表某种资源所有权,因此并非所有原始指针的使用都是错误的,如果您只需要指向其他人拥有的对象,则原始指针非常合适。但如果你拥有该对象,那么你应该。通过为类本身赋予 RAII 语义,或者将其包装在智能指针中,获得它的适当所有权。
You should use RAII to handle all resource allocations.
Smart pointers are just one common special case of that rule.
And smart pointers are more than just
shared_ptr
. There are different smart pointers with different ownership semantics. Use the one that suits your needs. (The main ones arescoped_ptr
,shared_ptr
,weak_ptr
andauto_ptr
/unique_ptr
(prefer the latter where available). Depending on your compiler, they may be available in the standard library, as part of TR1, or not at all, in which case you can get them through the Boost libraries.And yes, you should absolutely use these. It costs you nothing (if done correctly, you lose zero performance), and it gains you a lot (memory and other resources are automatically freed, and you don't have to remember to handle it manually, and your code using the resource gets shorter and more concise)
Note that not every pointer usage represents some kind of resource ownership, and so not all raw pointer usage is wrong. If you simply need to point to an object owned by someone else, a raw pointer is perfectly suitable. But if you own the object, then you should take proper ownership of it, either by giving the class itself RAII semantics, or by wrapping it in a smart pointer.
您不能盲目地用
std::auto_ptr
替换每个原始指针。特别是,auto_ptr
在分配时转移所有权,这对于某些目的来说非常有用,但对于其他目的来说绝对不可行。存在多种智能指针(例如,shared_ptr、weak_ptr、auto_ptr/unique_ptr 等)是有原因的,每种智能指针都有不同的用途。 “原始”指针的一个主要弱点是它有如此多的不同用途(并且具有这种多功能性很大程度上是因为它对任何一个目的几乎没有帮助或根本没有帮助)。智能指针往往更加专业,这意味着它们可以更智能地做好一件事,但也意味着您必须为工作选择正确的指针,否则最终会完全做错事情。
You can't just blindly substitute
std::auto_ptr
for every raw pointer. In particular,auto_ptr
transfers ownership on assignment, which is great for some purposes but definitely not for others.There is a real reason there are several varieties of smart pointers (e.g., shared_ptr, weak_ptr, auto_ptr/unique_ptr, etc.) Each fulfills a different purpose. One major weakness of a "raw" pointer is that it has so many different uses (and has that versatility largely because it does little or nothing to assist in any one purpose). Smart pointers tend to be more specialized, which means they can be more intelligent about doing one thing well, but also means you have to pick the right one for the job or it'll end up dong the wrong things entirely.
智能指针允许自动定义它所引用的对象的生命周期。这是需要理解的主要内容。
所以,不,你不应该在任何地方使用智能指针,只有当你想要自动化对象的生命周期,而不是让一个对象在内部管理这些对象从出生到死亡时。它就像任何工具一样:它解决特定类型的问题,而不是所有问题。
对于每个对象,您应该考虑它将经历的生命周期,然后选择最简单、正确且有效的解决方案之一。有时它会是shared_ptr,因为您希望该对象被多个组件使用,并在不再使用时自动销毁。有时您只需要当前范围/父对象中的对象,因此scoped_ptr可能更合适。有时您只需要实例的一个所有者,因此 unique_ptr 是合适的。也许您会发现您知道一种可以定义/自动化对象生命周期的算法的情况,因此您将为它编写自己的智能指针。
例如相反的情况,使用池会禁止您使用 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< /a>
Smart pointers allows to define automatically the life-time of objects it refers to. That's the main thing to understand.
So, no, you shouldn't use smart pointers everywhere, only when you want to automate life-time of your objects instead of having, for example, an object managing those objects inside from birth to death. It's like any tool : it solves specific kind of problems, not all problems.
For each object, you should think about the life cycle it will go through, then choose one of the simplest correct and efficient solution. Sometimes it will be shared_ptr because you want the object to be used by several components and to be automatically destroyed once not used anymore. Sometimes you need the object only in the current scope/parent-object, so scoped_ptr might be more appropriate. Sometimes you need only one owner of the instance, so unique_ptr is appropriate. Maybe you'll find cases where you know an algorithm that might define/automate the lifetime of an object, so you'll write your own smart pointer for it.
For example of opposite case, using pools forbids you to use smart_ptr. Naked pointers might be a more welcome simple and efficient solution in this particular (but common in embedded software) case.
See this answer (from me) for more explainations : https://softwareengineering.stackexchange.com/questions/57581/in-c-is-it-a-reflection-of-poor-software-design-if-objects-are-deleted-manuall/57611#57611
即使我检查分配的内存块上的内存泄漏,是否真的应该使用它们?
是
智能指针的全部目的是,它帮助您实现RAII( SBRM),它基本上让资源本身承担其释放的责任,并且资源不必明确依赖于您记住 解除分配 它。
如果我不使用它们,这可以被视为编程弱点吗?
不,
如果您不使用智能指针(RAII),那么您自己显式管理资源并不是一个弱点,而是一个不便或不必要的麻烦。智能指针实现 RAII 的目的是提供高效且无麻烦的资源处理方式,如果您不使用它,您就不会使用它。强烈建议纯粹因为它提供的众多优势而使用它。
如果强烈推荐使用智能指针(例如:std::auto_ptr)我应该使用它们而不是每个裸指针吗?
是
您应该尽可能使用智能指针,因为使用它们没有任何缺点,而且有很多优点。
但不要使用
auto_ptr
因为它已经被弃用了!您可以根据需要使用各种其他智能指针。您可以参考上面的链接来了解更多关于它们的信息。Should they really be used, even if I check memory leaks on allocated memory blocks?
YES
The whole purpose of smart pointers is, it help you implement RAII(SBRM), which basically lets the resource itself take the responsibility of its deallocation and the resource doesn't have to rely on you explicitly remembering to deallocate it.
If I do not use them, can this be considered as programming weakness?
NO,
It is not a weakness but a inconvenience or unnecessary hassle to explicitly manage the resources by yourself if you are not using Smart pointers(RAII). The purpose of smart pointers to implement RAII is to provide efficient and hassle free way of handling resources and you would just not be making use of it if you are not using it. It is highly recommended to use it purely for the numerous advantages it provides.
If the smart pointers(ex: std::auto_ptr)are strongly recommended, should I use them instead of every naked pointer?
YES
You should use smart pointers wherever possible because simply there is no drawback of using them and just numerous advantages to use them.
Don't use
auto_ptr
though because it is already deprecated!! There are various other smart pointers available that you can use depending on the requirement. You can refer the link above to know more about them.这是一个棘手的问题,事实上目前有一种模式可以
到处使用智能指针并不会让事情变得更容易。聪明的
指针在某些情况下会有所帮助,但你当然不能仅仅
不假思索地在任何地方使用它们。有很多不同的类型
智能指针,你必须考虑哪一个是合适的
在任何情况下;即便如此,你的大部分指针(至少在典型的情况下)
我工作过的领域中的应用程序)应该是原始指针。
无论采用哪种方法,有几点都值得一提:
除非必要,否则不要使用动态分配。在许多
应用程序,唯一需要动态分配的东西
是具有特定生命周期的对象,由应用程序确定
逻辑。不要对具有值语义的对象使用动态分配。
关于实体对象,那些在实体中建模的对象
应用程序域:这些应该根据
到程序逻辑。不管是否有指向
他们与否。如果它们的破坏导致了问题,那么你就有了一个
程序逻辑中的某个地方出现错误(没有正确处理事件,
等),并且使用智能指针不会改变任何东西。
实体对象的典型示例可能是客户端连接
服务器在客户端连接时创建,在客户端连接时销毁
客户端断开连接。在许多这样的情况下,最合适的管理
将是
delete this
,因为它将接收的连接断开连接事件。 (持有指向此类对象的指针的对象
必须向其注册,以便获悉其
破坏。但这样的指针纯粹是为了导航,不应该
是智能指针。)
当人们尝试使用智能指针时,您通常会发现什么
内存泄漏无处不在;典型的参考计数器不会
处理周期,当然,典型的应用程序充满了周期:
Connection
将指向与其连接的Client
,并且Client
将包含其连接的Connection
列表。如果智能指针是boost::shared_ptr,那么还有一个明确的
悬空指针的风险:创建两个指针非常容易
boost::shared_ptr
到同一地址(这会产生两个计数器供参考)。
It's a tricky question, and the fact that there is currently a mode to
use smart pointers everywhere doesn't make things any easier. Smart
pointers can help in certain situations, but you certainly can't just
use them everywhere, without thinking. There are many different types
of smart pointers, and you have to think about which one is appropriate
in every case; and even then, most of your pointers (at least in typical
applications in the domains I've worked in) should be raw pointers.
Regardless of the approach, several points are worth mentionning:
Don't use dynamic allocation unless you have to. In many
applications, the only things that need to be allocated dynamically
are objects with specific lifetimes, determined by the application
logic. Don't use dynamic allocation for objects with value semantics.
With regards to entity object, those which model something in the
application domain: these should be created and destructed according
to the program logic. Irregardless of whether there are pointers to
them or not. If their destruction causes a problem, then you have an
error in your program logic somewhere (not handling an event correctly,
etc.), and using smart pointers won't change anything.
A typical example of an entity object might be client connection in a
server, is created when the client connects, and destructed when the
client disconnects. In many such cases, the most appropriate management
will be a
delete this
, since it is the connection which will receivethe disconnection event. (Objects which hold pointers to such an object
will have to register with it, in order to be informed of its
destruction. But such pointers are purely for navigation, and shouldn't
be smart pointers.)
What you'll usually find when people try to use smart pointers
everywhere is that memory leaks; typical reference counters don't
handle cycles, and of course, typical applications are full of cycles: a
Connection
will point to theClient
which is connected to it, andthe
Client
will contain a list ofConnection
where it is connected.And if the smart pointer is
boost::shared_ptr
, there's also a definiterisk of dangling pointers: it's far to easy to create two
boost::shared_ptr
to the same address (which results in two countersfor the references).
在我看来,是的,您应该为您拥有的每个指针使用它。
以下是我对 C++ 资源管理的想法(如有不同意见,请随意):
这导致了以下实践:
使
boost::scoped_ptr
成为本地变量和成员变量的默认选择。请记住,使用scoped_ptr
作为成员变量将使您的类不可复制。如果您不希望这样做,请参阅下一点。对容器使用
boost::shared_ptr
或启用共享所有权:// MyClass* 指针的容器:
typedef boost::shared_ptr
std::vector; vec;
std::auto_ptr
(C++03) 可用于所有权转移。例如作为工厂或克隆方法的返回值://工厂方法返回auto_ptr
std::auto_ptr<按钮>按钮 = Button::Create(...);
// Clone方法返回auto_ptr
std::auto_ptr;复制 = obj->clone();
// 使用release()将所有权转移到scoped_ptr或shared_ptr
boost::scoped_ptr
如果您需要存储不属于您的指针,则可以使用原始指针:
this->parent = inParentObject;
在某些情况下,需要
boost::weak_pointer
。有关详细信息,请参阅文档。In my opinion, yes, you should it for every pointer that you own.
Here are my ideas on resource management in C++ (feel free to disagree):
This leads to the following practices:
Make
boost::scoped_ptr
the default choice for local and member variables. Do keep in mind that usingscoped_ptr
for member variables will make your class non-copyable. If you don't want this see next point.Use
boost::shared_ptr
for containers or to enable shared ownership:// Container of MyClass* pointers:
typedef boost::shared_ptr<MyClass> MyClassPtr;
std::vector<MyClassPtr> vec;
The
std::auto_ptr
(C++03) can be used for ownership transfer. For example as the return value of factory or clone methods:// 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());
If you need to store a pointer that you don't own then you can use a raw pointer:
this->parent = inParentObject;
In certain situations a
boost::weak_pointer
is required. See the documentation for more information.一般来说,您应该更喜欢智能指针,但也有一些例外。
如果您需要重新转换指针,例如提供 const 版本,那么使用智能指针几乎不可能做到这一点。
智能指针用于控制对象的生命周期。通常,当您将指针传递给函数时,该函数不会影响生命周期;该函数不会尝试删除该对象,也不会存储指针的副本。在函数返回之前,调用代码无法删除该对象。在这种情况下,哑指针是完全可以接受的。
In general you should prefer smart pointers, but there are a couple of exceptions.
If you need to recast a pointer, for example to provide a
const
version, that becomes nearly impossible with smart pointers.Smart pointers are used to control object lifetime. Often when you are passing a pointer to a function, the function will not affect the lifetime; the function does not try to delete the object, and it does not store a copy of the pointer. The calling code cannot delete the object until the function returns. In that case a dumb pointer is perfectly acceptable.
是的。假设您有可用的 C++0x,请使用
unique_ptr
或shared_ptr
(视情况而定)来包装您new
的所有原始指针。在make_shared
的帮助下,shared_ptr
具有高性能。如果您不需要引用计数,那么unique_ptr
将为您带来更好的性能。它们在集合和其他auto_ptr
是哑指针的情况下都表现良好。Yes. Assuming you have C++0x available to you, use
unique_ptr
orshared_ptr
(as appropriate) to wrap all the raw pointers younew
up. With the help ofmake_shared
,shared_ptr
is highly performant. If you don't need reference counting thenunique_ptr
will get you better perf. Both of them behave properly in collections and other circumstances whereauto_ptr
was a dumb pointer.到处使用智能指针(shared_ptr 或其他)是一个坏主意。使用shared_ptr来管理对象/资源的生命周期是很好的,但是将它们作为参数传递给函数等并不是一个好主意。这增加了循环引用和其他极难跟踪的错误的可能性(个人经验:尝试找出谁如果每个函数调用都会更改引用计数,则不应该在 200 万行代码中保留一个资源 - 您最终会认为做这种事情的人都是 m***ns)。最好传递原始指针或引用。
当与惰性实例化结合使用时,情况会更糟。
我建议开发人员应该了解他们编写的对象的生命周期,并使用shared_ptr来控制它(RAII),但不要将shared_ptr的使用扩展到此之外。
Using smart pointers (shared_ptr or otherwise) EVERYWHERE is a bad idea. It's good to use shared_ptr to manage the lifetime of objects/resources but it's not a good idea to pass them as parameters to functions etc. That increases the likelihood of circular references and other extremely hard to track bugs (Personal experience: Try figuring out who should not be holding onto a resource in 2 millions lines of code if every function invocation changes the reference count - you will end up thinking the guys who do this kind of thing are m***ns). Better to pass a raw pointer or a reference.
The situation is even worse when combined with lazy instantiation.
I would suggest that developers should know the lifecycle of the objects they write and use shared_ptr to control that (RAII) but not extend shared_ptr use beyond that.