可选元素是否会破坏 RAII?如果是,更好的方法是什么?

发布于 2024-10-04 03:40:41 字数 363 浏览 7 评论 0原文

我有一个二维细胞矩阵。通常只有不可见的算法才能处理这些单元。但有时我想可视化每个单元格,因此我添加了一个指向图形对象的指针。

class Cell
{
   ...
   QAbstractGraphicsItem* representation_;
   ...
}

Cell 的构造函数将representation_ 设置为 0。有时,另一个可视化类会迭代矩阵,并向 Cells 添加元素,通过颜色可视化每个单元格的内容。

我认为这打破了 RAII 范式。你有更好的方法吗?

我可以创建另一个二维矩阵,并从那里链接到原始矩阵,以便指针位于可视化一侧,但我需要两个矩阵。

I have a 2-dimensional matrix of cells. Usually only invisible algorithms work with these cells. But sometimes I want to visualize each cell so I added a pointer to a graphical object

class Cell
{
   ...
   QAbstractGraphicsItem* representation_;
   ...
}

The constructor of Cell sets representation_ to 0. Sometimes another Visualization class iterates on the matrix and adds elements to Cells that visualize the content of each cell by colors.

I think this breaks the RAII paradigma. Do you have a better approach?

I could create another 2-dimensional matrix and from there link to the original matrix so that the pointers are on the visualization side but I would need two matrices then.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

魔法唧唧 2024-10-11 03:40:41

正如(我认为)Scott Meyers 指出的那样,RAII 的命名是错误的。

不应该叫“资源获取就是初始化”,而应该叫“销毁就是资源释放”。但我们就在我们所在的地方。

如果 Cell“拥有”由 representation_ 指向的对象,并在其析构函数中删除它,那么这仍然是 RAII 的一种形式,就像初始化 shared_ptr 一样。 code> 带有一个空指针,然后将其设置为其他内容。我假设您正确使用它(确保对象在创建后立即保存到某个 Cell 或其他单元中,在构造函数完成和指针最终将被释放的地方存储之间不会出现失败)。如果是这样,您正在使用 RAII 的重要部分,即使它不是构造函数来完成这项工作。

这可能违反了单一责任原则。您已让 Cell 负责表示单元格,并负责管理此 QAbstractGraphicsItem 对象的内存。将 representation_ 更改为智能指针类型可能会简化事情,因此 Cell 的析构函数中不需要任何特殊代码。

如果 Cell 不“拥有”representation_ 指向的对象,那么本质上也不会违反 RAII,它只是没有实现它。其他东西必须负责该对象的所有权。也许其他东西使用了 RAII,也许它违反了它。为了确保对象在 Cell 需要的时候一直存在,它必须以某种方式参与到 Cell 的生命周期中(例如,如果它拥有该 Cell,那么你可能没问题)。因此,如果不是,则很可能以某种方式违反了 RAII。

RAII is misnamed, as (I think) Scott Meyers points out.

It shouldn't be called "Resource Acquisition is Initialization", it should be called "Destruction is Resource Release". But we are where we are.

If the Cell "owns" the object pointed to by representation_, and deletes it in its destructor, then this is still a form of RAII, the same way that you can initialize a shared_ptr with a null pointer, then later set it to something else. I assume you use it correctly (ensure that the object is saved to some Cell or other immediately after it is created, with no chance of failure between the completion of the constructor and the storing of the pointer somewhere it will be eventually freed). If so, you're using the important part of RAII, even though it's not a constructor doing the work.

It's probably a violation of the single responsibility principle. You've made Cell responsible for representing a cell, and also for memory-managing this QAbstractGraphicsItem object. It would probably simplify things to change representation_ to a smart pointer type, so there's no need for any special code in the destructor of Cell.

If the Cell doesn't "own" the object pointed to by representation_, then that doesn't inherently violate RAII either, it just doesn't implement it. Something else will have to be responsible for ownership of the object. Maybe that other thing uses RAII, maybe it violates it. For the thing to ensure the object lives as long as the Cell needs it, it would have to be involved somehow in the lifecycle of the Cell (for instance, if it owns the cell then you might be fine). So if it isn't, there's a good chance it's violating RAII somehow.

失而复得 2024-10-11 03:40:41

我认为您正在寻找Visitor设计模式

I think you are looking for the Visitor design pattern.

末骤雨初歇 2024-10-11 03:40:41

我认为你根本就不会破坏RAII(资源获取即初始化),只要你的 Cell 析构函数实际上删除了 QAbstractGraphicsItem 对象(它的析构函数是虚拟的,对吧?)(如果有的话) 。但是,您似乎担心此架构中的图形项和单元之间的潜在耦合。

是的,将对象存储与其表示完全分离是很有吸引力的。实现此目的的完美工具(正如 Ben Voigt 所指出的)是让您可以使用额外的数据元素从类外部扩展类定义。但C++不支持这个。我能想到的最好的建议是为可视化指针保留另一个矩阵,但是您必须维护第二个数据结构。如果您不想这样做,则需要为了实用的简单性而牺牲这种完美的分离。

假设您在任何时候都只有一个活动的可视化,我认为在单元格中保留单个指针以供可视化系统使用没有问题。你的代码按原样就很好。是的,您将数据存储和表示捆绑在一起,但这是一个非常松散的链接。除了识别该层存在并且可能想要存储一些(不透明的)特定于单元格的数据之外,您的单元格仍然不依赖于与表示相关的任何内容。

为了解决其他建议,访问者模式对于设计可视化工具很有用,但这是一个正交设计点。如果这些访问者需要为每个单元存储额外的数据怎么办?这才是真正的问题。至于使用地图模拟属性扩展,它很复杂,而且也没有必要,除非您在单个矩阵上同时运行多个可视化。

I don't think you're breaking RAII (Resource Acquisition Is Initialization) at all, as long as your Cell destructor actually deletes the QAbstractGraphicsItem object (its destructor is virtual, right?) if one is there. However, you appear to be concerned about the potential coupling between your graphics items and cells in this architecture.

Yes, it's attractive to completely separate the object store from its presentation. The perfect tool for this (as pointed out by Ben Voigt) is something that lets you extend your class definition, from outside the class, with an extra data element. But C++ doesn't support this. Your suggestion to keep another matrix for the visualization pointers is the best I can think of, but then you have to maintain this second data structure. If you don't want to do this, you're going to need to sacrifice this perfect separation for practical simplicity.

Assuming you only have one visualization active at any time, I don't see a problem with keeping a single pointer in your Cells for use by the visualization system. Your code is fine as-is. Yes, you are tying together the data storage and presentation, but it's a pretty loose link. Your cells still don't depend on anything relating to presentation, other than recognizing that the layer exists and might want to store some (opaque) Cell-specific data.

To address other suggestions, the visitor pattern is useful for designing the visualizers, but that's an orthogonal design point. What if those visitors need to store extra data per-cell? That's the real question. As for simulating a property extensions with a map, it's complicated, and it's also not necessary unless you have multiple visualizations operating concurrently on a single matrix.

心是晴朗的。 2024-10-11 03:40:41

听起来您想要扩展属性,也许保存 Cell 或矩阵算法不需要的颜色信息。这是一种非常动态的语言方法。

C++ 等静态语言的常用方法是子类化 Cell。您的算法应该可以在 CellSubclass 矩阵上正常工作,尽管如果您在数组中按值顺序存储元素,事情会变得有点复杂。您可以继续这样做并将算法模板化,或者可以将指针存储在数组中。

不过,如果您确实想要扩展属性,则可以在 Cell 内使用 map,其中 IPropertyValue 只是提供虚拟析构函数,以便在释放 Cell 时不会泄漏扩展属性值。检索值时需要进行强制转换。使用某个私有静态变量的地址作为密钥,以保证唯一性和一致性。

编辑:如果您只想/需要存储一个指针,那么您所采用的方法将会很好地工作。但使用智能指针,并在赋值时使用swap。这样一切都将是 RAII。

Sounds like you are wanting extension properties, perhaps holding color information that isn't needed by Cell or the matrix algorithms. It's a very dynamic-languagy approach.

The usual approach for static languages like C++ would be to subclass Cell. Your algorithms should work just fine on a matrix of CellSubclass, although it complicates matters a little bit if you were storing elements sequentially by value in an array. You can continue doing that and templatize your algorithms, or you can store pointers in the array.

If you really want extension properties, though, you can use a map<void*,IPropertyValue*> inside Cell, where IPropertyValue simply provides a virtual destructor so that you don't leak the extension property values when freeing a Cell. You'll need to cast when retrieving the value. Use the address of some private static variable as the key, to guarantee uniqueness and uniformity.

EDIT: If you only want/need to store one pointer, then the way you have will work well. But use a smart pointer, and use swap when assigning it. That way everything will be RAII.

∝单色的世界 2024-10-11 03:40:41

它确实破坏了 RAII - 您应该使用自释放指针。

It does break RAII- you should use a self-releasing pointer.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文