什么是隐式共享?
我正在用 C++ 构建一个游戏引擎库。不久前,我使用 Qt 构建一个应用程序,并对它的隐式共享的使用非常着迷。 。我想知道是否有人可以更详细地解释这项技术,或者可以提供一个简单的实际例子。
I am building a game engine library in C++. A little while back I was using Qt to build an application and was rather fascinated with its use of Implicit Sharing. I am wondering if anybody could explain this technique in greater detail or could offer a simple example of this in action.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
隐式共享背后的关键思想似乎是使用更常见的术语“写时复制”。写时复制背后的想法是让每个对象充当指向实际实现的指针的包装器。每个实现对象都会跟踪指向它的指针的数量。每当对包装对象执行操作时,它都会转发到执行对象,由执行对象执行实际工作。
这种方法的优点是复制和销毁这些对象的成本很低。要创建对象的副本,我们只需创建一个包装器的新实例,将其指针设置为指向实现对象,然后增加指向该对象的指针数量(有时称为 顺便说一下,引用计数)。销毁是类似的 - 我们将引用计数减一,然后查看是否有其他人指向实现。如果没有,我们就释放其资源。否则,我们什么也不做,只是假设其他人稍后会进行清理工作。
这种方法的挑战在于,这意味着多个不同的对象将全部指向同一个实现。这意味着如果有人最终对实现进行了更改,则引用该实现的每个对象都会看到更改 - 这是一个非常严重的问题。为了解决这个问题,每次执行可能会更改实现的操作时,该操作都会通过查看引用计数是否相同为 1 来检查是否有任何其他对象也引用该实现。如果没有其他对象引用该对象,则操作可以继续进行 - 更改不可能传播。如果至少有一个其他对象引用该数据,则包装器首先为自身进行实现的深层复制,并更改其指针以指向新对象。现在我们知道不能进行任何共享,并且可以轻松进行更改。
如果您想查看一些实际示例,请查看 中的讲座示例 15.0 和 16.0斯坦福大学的 C++ 编程入门课程。它展示了如何使用这种技术设计一个对象来保存单词列表。
希望这有帮助!
The key idea behind implicit sharing seems to go around using the more common term copy-on-write. The idea behind copy-on-write is to have each object serve as a wrapper around a pointer to the actual implementation. Each implementation object keeps track of the number of pointers into it. Whenever an operation is performed on the wrapper object, it's just forwarded to the implementation object, which does the actual work.
The advantage of this approach is that copying and destruction of these objects are cheap. To make a copy of the object, we just make a new instance of a wrapper, set its pointer to point at the implementation object, and then increment the count of the number of pointers to the object (this is sometimes called the reference count, by the way). Destruction is similar - we drop the reference count by one, then see if anyone else is pointing at the implementation. If not, we free its resources. Otherwise, we do nothing and just assume someone else will do the cleanup later.
The challenge in this approach is that it means that multiple different objects will all be pointing at the same implementation. This means that if someone ends up making a change to the implementation, every object referencing that implementation will see the changes - a very serious problem. To fix this, every time an operation is performed that might potentially change the implementation, the operation checks to see if any other objects also reference the implementation by seeing if the reference count is identically 1. If no other objects reference the object, then the operation can just go ahead - there's no possibility of the changes propagating. If there is at least one other object referencing the data, then the wrapper first makes a deep-copy of the implementation for itself and changes its pointer to point to the new object. Now we know there can't be any sharing, and the changes can be made without a hassle.
If you'd like to see some examples of this in action, take a look at lecture examples 15.0 and 16.0 from Stanford's introductory C++ programming course. It shows how to design an object to hold a list of words using this technique.
Hope this helps!