【发布时间】: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<QPixmap>?
更新:
详细说明: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