【问题标题】:Dereferencing shared pointer and call by reference取消引用共享指针和引用调用
【发布时间】:2020-05-06 12:01:22
【问题描述】:

我使用了一些 QMapControl 的分支并发现了一个错误。 GeometryPointImage 有图像 const QPixmap& image() const 的吸气剂:

const QPixmap& GeometryPointImage::image() const
{
    // Is the image pixmap currently null?
    if (m_image == nullptr) { //std::shared_ptr<QPixmap> m_image;
        // Have we already constructed the null image pixmap?
        if (m_image_null == nullptr) { //std::unique_ptr<QPixmap> m_image_null;
            // Construct the null image pixmap.
            m_image_null.reset(new QPixmap);
        }
        // Return the null image pixmap.
        return *(m_image_null.get());
    } else {
        // Return the image pixmap.
        return *(m_image.get());
    }
}

m_image有多种setter,image()getter用于draw()函数:

painter.drawPixmap(-pixmap_rect_px.rawRect().width() / 2.0, -pixmap_rect_px.rawRect().height() / 2.0, image()); // void drawPixmap(int x, int y, const QPixmap &pm)

我可以捕捉到这样的行为:draw() 函数调用 image() 取消引用共享指针,它进入 drawPixmap 和其他一些事件调用 setImage() 其中m_image 分配给新值,并析构共享指针破坏由drawPixmap() 引用的QPixmap 对象,然后应用程序进入SIGSEGV。

我认为返回对共享指针所拥有的东西的引用的 getter 并不是很好的做法,但最合适的解决方案是什么?我不想复制QPixMap 对象或将互斥锁添加到getter、setter 和draw() 中。有没有办法延长引用对象的寿命(可能类似于qAsConst)? getter 是否应该返回std::shared_ptr&lt;QPixmap&gt;

更新: 详细说明:setImage() 是从主线程调用的,并且此设置器预计会发出信号以重绘对象。但是QMapControl main class 也使用QtConcurrent::run() 来重绘整个场景,并且它触及了来自其他线程的像素图。当线程例如线程#1删除对象时#6(或#7)是drawPixmap()

【问题讨论】:

  • _ 它进入drawPixmap 和其他一些事件调用setImage()_ 虽然drawPixmap() 绘制图像不应该有任何其他事件。事件排队(每个线程),事件循环是最顶层的调用者。因此,在处理一个事件时,不能处理其他事件。大多数 GUI 的东西不是为多线程设计的,因此不是线程安全的。如果要添加多线程,则必须在外部自行管理。
  • 我认为返回对共享指针所拥有的东西的引用的getter不是这样的好习惯如果getter的类是所有者之一,我看不到危险. const 引用通常容易出现生命周期问题。如果被引用的对象由于任何原因被销毁,那么 const 引用就会变得悬空。 std::shared_ptr 对这一事实没有额外贡献,恕我直言。

标签: c++ qt shared-ptr


【解决方案1】:

好吧,我现在不希望有人对这个问题给出另一个答案,所以让我的解决方案,它可能会帮助以后遇到这样问题的人:

std::shared_ptr<QPixmap> GeometryPointImage::image() const
{
    // Is the image pixmap currently null?
    if (m_image == nullptr)
    {
        // Have we already constructed the null image pixmap?
        if (m_image_null == nullptr)
        {
            // Construct the null image pixmap.
            m_image_null.reset(new QPixmap);
        }

        // Return the null image pixmap.
        return std::make_shared<QPixmap>(*m_image_null.get());
    }
    else
    {
        // Return the image pixmap.
        return m_image;
    }
}

....

painter.drawPixmap(-pixmap_rect_px.rawRect().width() / 2.0, -pixmap_rect_px.rawRect().height() / 2.0, *image());

现在,返回 shared_ptr 会延长 QPixMap 的生命周期,即使它已被其他东西重置。而且,image() 方法只在课堂上使用,外部没有,所以很容易解决这个问题。

【讨论】:

    猜你喜欢
    • 2018-12-22
    • 1970-01-01
    • 2018-12-08
    • 1970-01-01
    • 1970-01-01
    • 2013-02-20
    • 2019-05-20
    • 1970-01-01
    相关资源
    最近更新 更多