如何应对返回指针的生命周期?

时间:2012-06-04 07:31:15

标签: c++ reference lifetime

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

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作为图像传递。

感谢。

3 个答案:

答案 0 :(得分: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或者有可用的默认值可以返回以表明不存在时,这才是可行的。

小点,所有成员函数都暗示他们不会更改Image所以请考虑将它们const

答案 1 :(得分:1)

RAII绝对是走到这里的方式。您的Pixel类应该在其析构函数中调用image.returnPixel(this)findPixel应该返回shared_ptr<Pixel>。如果用户完成后可能无法删除像素,则可以使用不删除Pixel的自定义删除工具返回shared_ptr,而是调用returnPixel

答案 2 :(得分:1)

{@ 1}}之类的迭代器显然在向量被破坏时失效,我不知道这与你的情况有多大不同。

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


我们已经针对std::vector提出了建议,如果你采取这种方式,那么返回shared_ptr而不是weak_ptr似乎是一个很好的决定,因为所有权属于图片。