1

我正在制作一组类来表示图像。此类的一个应用是在一组平铺图像上绘制图片。抽象图像类看起来像这样:

class Image
{
public:
    virtual Pixel* findPixel( Point p ) =0;
    virtual bool isDrawable( Point p ) =0;
    virtual bool contains( Point p ) =0;
};

我预见到的问题是,如果我开设这样的课程:

class TiledImage : public Image
{
    std::vector<Image*> tiles;

public:
    Pixel* findPixel( Point p )
    {
        // find the tile that contains the point.
        // ask it for the pixel that contains the point.
        // return the pixel.
    }

    // etc....

};

旨在根据需要创建、保存和删除非常大图像的子部分(图块),那么用户可以存储指向最终可能不再存在的 Pixel 对象的指针。

一种选择是要求用户在完成后重新检查像素,例如:

Pixel* p = image.findPixel( aPoint );
// do stuff
image.returnPixel( p ); // p is not guaranteed to be valid after this point.
p->doSomething(); // this is not guaranteed to work.

我不太喜欢这样,因为如果用户不返回像素,那么它可能真的会干扰平铺图像的操作——忘记返回像素可能会导致它完全锁定,因为它不会无法删除不再需要的图块。它们将被锁定以保证指向像素的指针保持有效。用户可能很难发现锁定的原因。

此外,这种关注有点专业。在典型情况下,在图像消失之前,您不会期望像素消失。

有没有更好的方法来处理这种情况?智能指针?不要以某种方式返回参考?首先让 TiledImage 从 Image 继承没有意义吗?当我希望图形非常大时,我当然希望能够将 TiledImage 作为图像传递。

谢谢。

4

3 回答 3

5

两种可能性(至少):

  • 使用shared_ptrbooststd):

    std::vector<shared_ptr<Image>> tiles; // No longer have to explicitly
                                          // delete the elements.
    
    shared_ptr<Pixel> findPixel( Point p )
    {
        ...
    }
    
    shared_ptr<Pixel> p = image.findPixel( aPoint ); 
    p->doSomething(); // Fine, as the internal pointer will not be
                      // deleted due to use of the smart pointer.
    
  • 返回的副本Pixel。这只有在Pixel始终期望找到 a 或者如果有可用的默认值可以返回以指示不存在时才可行。

次要的一点,所有成员函数都暗示它们不会改变Image,所以考虑制作它们const

于 2012-06-04T07:34:25.520 回答
1

当向量被销毁时,诸如此类的迭代器std::vector显然会失效,我看不出这与您的情况有何不同。

我的建议是通过引用返回像素,因为这清楚地表明它没有移交所有权。此外,请提供有关失效行为的良好文档。


有一些关于 的建议,如果你采取这条路线,返回 a而不是 ashared_ptr似乎是一个不错的决定,因为所有权属于图像。weak_ptrshared_ptr

于 2012-06-04T07:41:13.367 回答
1

RAII 绝对是通往这里的道路。你的 Pixel 类应该调用image.returnPixel(this)它的析构函数并且findPixel应该返回一个shared_ptr<Pixel>. 如果用户完成后可能无法删除像素,则可以改为返回带有自定义删除器的 shared_ptr,该删除器不会删除像素,而是调用returnPixel

于 2012-06-04T07:33:57.013 回答