C ++中的内存管理模式 [英] Memory management patterns in C++

查看:85
本文介绍了C ++中的内存管理模式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想我对正常(功能)设计图案有相当的经验,在四本书的帮派,我主要用于java和C#。在这些管理语言中,这几乎是您需要知道的完成工作的一切。



然而,在C ++世界中,开发人员还可以控制所有对象被分配,传递和删除。我了解原则(我在其他文本中阅读了 Stroutrup ),但仍然需要大量的努力来决定哪种机制对于给定的情景是最好的 - 这是一个内存相关设计模式的组合将是有用的。



例如,昨天我不得不创建一个类结果,这是另一种类型对象的几个对象和一个集合(在这种情况下为std :: vector)的容器。所以有几个设计问题我无法真正回答:


  1. 我应该通过值还是通过智能指针返回这个类? / li>
  2. 在课堂里面,矢量和对象是正常的成员,还是应该将它们作为智能指针重新存储?

  3. 在向量中,应该我直接将对象直接存储在对象上,或者将智能指针重新存储在其中?

  4. 我的结果类中定义的getter应该返回哪个值(即值,引用或智能指针)?

当然,智能指针很酷,没有什么,但是它们创建语法混乱,我不确定如果为每个单个对象使用malloc是最佳方法。 / p>

我将不胜感激上述具体要点的答案,但更多的是关于内存相关设计模式的更长和更一般的文本,以便我可以解决问题我也会在星期一!

解决方案

所有的问题最终都是一样的:这取决于是否需要引用语义或值语义(需要考虑一些注意事项)。 p>

如果您需要引用语义,这是您默认使用Java和C#语言(UDTs(用户定义的数据类型))声明的关键字,那么你将不得不去智能指针。在这种情况下,您希望多个客户端将安全别名保存到特定对象,其中安全这个单词封装了这两个要求:


  1. 避免悬挂引用,以便您不会尝试访问不存在的对象;

  2. 避免超过所有引用他们,这样你就不会泄漏记忆。

这是什么智能指针 。如果您需要参考语义(如果您的算法不是这样,使得引用的开销在需要共享所有权的情况下重要),那么您应该使用智能指针。 / p>

您确实需要引用语义,例如,当您希望将同一对象作为多个集合的一部分时。当您更新一个集合中的对象时,您希望始终更新所有其他集合中同一对象的表示。在这种情况下,您可以将智能指针存储在这些集合中的对象中。智能指针封装对象的标识,而不是其值。



但是,如果不需要创建别名,那么值语义可能是你应该依赖的。这是您在C ++中默认使用自动存储(即在堆栈中)声明的值。



需要考虑的是STL集合存储>值,所以如果你有一个向量< T> ,那么 T 将存储在您的矢量中。总是假设你不需要参考语义,如果你的对象大而复杂的话,这可能会变成一个开销。



为了限制这种情况的可能性, C ++ 11自带的移动操作,这使得有可能在不需要对象的旧副本时有效地传输对象。






我现在将尝试使用上述概念来更直接地回答您的问题。



1)我应该通过值还是通过智能指针返回这个类?



这取决于是否需要引用语义。该功能对该对象有什么作用?该功能返回的对象是否应由许多客户端共享?如果是这样,那么通过智能指针。如果没有,是否可以定义有效的移动操作(这几乎总是这样)?如果是这样,那么按值。如果没有,通过智能指针。



2)在课堂内,矢量和对象是正常的成员,还是应该将它们作为智能指针再次存储?



很可能是正常成员,因为向量通常意在概念上是您对象的一部分,因此它们的生命周期必须与嵌入它们的对象。在这种情况下,很少需要引用语义,但是如果这样做,则使用智能指针。



3)在向量中,应该直接存储对象,还是智能指针给他们?



与第1点相同的答案):你需要共享这些对象吗?你应该将别名存储到这些对象吗?你想要更改这些对象,在你的代码的不同部分看到哪些引用这些对象?如果是这样,那么使用共享指针。如果没有,是否可以有效地复制和/或移动这些对象?如果是(大部分时间),存储值。如果没有,请存储智能指针。



4)我的结果类中定义的getter应该返回什么(即值,引用或智能指针)? >



与第2点相同的答案):这取决于您计划对返回的对象做什么:您希望它们被代码的许多部分共享?如果是这样,返回一个智能指针。如果只有一部分完全拥有,则按价值返还,除非移动/复制这些对象太贵或根本不允许(很不可能)。在这种情况下,返回一个智能指针。






作为附注,请注意,C ++中的智能指针是比Java / C#引用更棘手:首先,你有两个主要的智能指针,取决于是否共享所有权 shared_ptr )或独特所有权 unique_ptr )。其次,您需要避免循环引用 shared_ptr ,这将创建保持对方的对象的岛屿,即使您的运行代码无法访问。这就是为什么存在弱指针( weak_ptr )的原因。



导致责任的概念,用于管理对象的生命周期或(更一般地)管理已使用资源。您可能想要阅读RAII惯例(资源获取是初始化),以及一般的异常处理(写入异常安全代码是存在这些技术的主要原因之一)。


I think I have a considerable experience with normal (functional) designed patters, as described e.g. in the gang of four book, which I mainly used in java and C#. In these "managed" languages this is pretty much everything you need to know to get your work done.

However, in C++ world the developer also has the control of how all the objects get allocated, passed around and deleted. I understand the principles (I read Stroutrup among other texts), but it still takes me a lot of effort to decide which mechanism is best for a given scenario - and this is where a portfolio of memory-related design patterns would be useful.

For example, yesterday I had to create a class Results, that was a container for a few objects and a collection (std::vector in this case) of yet another type of objects. So there are a few design questions I couldn't really answer:

  1. Should I return this class by value, or by smart pointer?
  2. Inside the class, should the vector and the objects be normal members, or should they be stored as smart pointers again?
  3. In the vector, should I store the objects directly, or smart pointers to them again?
  4. What should the getters defined on my Results class return (i.e. values, references or smart pointers)?

Of course, smart pointers are cool and what not, but they create syntactic clutter and I am not convinced if using malloc for every single object is optimal approach.

I would be grateful for answers for the specific points above, but even more for some longer and more general texts on memory-related design patterns - so that I can solve the problems I will have on Mondays as well!

解决方案

The answer to all of your questions ends up being one and the same: it depends on whether you need reference semantics or value semantics (with some caveats to be taken into account).

If you need reference semantics, which is what you have by default in languages like Java and C# for UDTs (User-defined Data Types) declared with the class keyword, then you will have to go for smart pointers. In this scenario you want several clients to hold safe aliases to a specific object, where the word safe encapsulates these two requirements:

  1. Avoid dangling references, so that you won't try to access an object that doesn't exist anymore;
  2. Avoid objects which outlive all of the references to them, so that you won't leak memory.

This is what smart pointers do. If you need reference semantics (and if your algorithms are not such to make the overhead of reference counting significant where shared ownership is needed), then you should use smart pointers.

You do need reference semantics, for instance, when you want the same object to be part of several collections. When you update the object in one collection, you want the representations of the same object in all the other collections to be consistently updated. In this case, you store smart pointers to your objects in those collections. Smart pointers encapsulate the identity of an object rather than its value.

But if you do not need to create aliases, then value semantics is probably what you should rely on. This is what you get by default in C++ when you declare an object with automatic storage (i.e. on the stack).

One thing to consider is that STL collections store values, so if you have a vector<T>, then copies of T will be stored in your vector. Always supposing that you do not need reference semantics, this might become anyway an overhead if your objects are big and expensive to copy around.

To limit the likelyhood of this scenario, C++11 comes with move operations, which make it possible to efficiently transfer objects by value when the old copy of the object is no more needed.


I will now try to use the above concepts to answer your questions more directly.

1) Should I return this class by value, or by smart pointer?

It depends on whether you need reference semantics or not. What does the function do with that object? Is the object returned by that function supposed to be shared by many clients? If so, then by smart pointer. If not, is it possible to define an efficient move operation (this is almost always the case)? If so, then by value. If not, by smart pointer.

2) Inside the class, should the vector and the objects be normal members, or should they be stored as smart pointers again?

Most likely as normal members, since vectors are usually meant to be conceptually a part of your object, and their lifetime is therefore bound to the lifetime of the object that embeds them. You rarely want reference semantics in such a scenario, but if you do, then use smart pointers.

3) In the vector, should I store the objects directly, or smart pointers to them again?

Same answer as for point 1): do you need to share those objects? Are you supposed to store aliases to those objects? Do you want changes to those objects to be seen in different parts of your code which refer those objects? If so, then use shared pointers. If not, is it possible to efficiently copy and/or move those objects? If so (most of the time), store values. If not, store smart pointers.

4) What should the getters defined on my Results class return (i.e. values, references or smart pointers)?

Same answer as for point 2): it depends on what you plan to do with the returned objects: do you want them to be shared by many parts of your code? If so, return a smart pointer. If they shall be exclusively owned by just one part, return by value, unless moving/copying those objects is too expensive or not allowed at all (quite unlikely). In that case, return a smart pointer.


As a side note, please be aware that smart pointers in C++ are a bit trickier than Java/C# references: first of all, you have two main flavors of smart pointers depending on whether shared ownership (shared_ptr) or unique ownership (unique_ptr) is desired. Secondly, you need to avoid circular references of shared_ptr, which would create islands of objects that keep each other alive even though they are no more reachable by your running code. This is the reason why weak pointers (weak_ptr) exist.

These concept naturally lead to the concept of responsibility for managing the lifetime of an object or (more generally) the management of a used resource. You might want to read about the RAII idiom for instance (Resource Acquisition Is Initialization), and about exception handling in general (writing exception-safe code is one of the main reasons why these techniques exist).

这篇关于C ++中的内存管理模式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆