看来您在 Qt 中发现了一个错误。我建议你提交一个错误报告并参考这个有点相关的错误:https ://bugreports.qt.io/browse/QTBUG-14637
问题似乎出在http://code.qt.io/cgit/qt/qtbase.git/tree/src/corelib/tools/qsharedpointer_impl.h?h=v5.5.1#n420 - 其简化代码如下所示:
static inline QSharedPointer create()
{
typedef QtSharedPointer::ExternalRefCountWithContiguousData<T> Private;
typename Private::DestroyerFn destroy = &Private::deleter;
QSharedPointer result(Qt::Uninitialized);
result.d = Private::create(&result.value, destroy);
new (result.data()) T();
result.d->setQObjectShared(result.value, true);
result.enableSharedFromThis(result.data());
return result;
}
对其他函数的引用(主要在同一个文件中)有点复杂,但它似乎deleter
存储在result
构造函数被放置之前new
。当您的构造函数抛出时,您的对象永远不会完全构造,但是QSharedPointer result
已经构造了,并且包含删除器。deleter
从那里到函数有一小段距离:
static void deleter(ExternalRefCountData *self)
{
ExternalRefCountWithContiguousData *that =
static_cast<ExternalRefCountWithContiguousData *>(self);
that->data.~T();
}
现在你的析构函数被调用了,尽管你的构造函数从未完成。那是未定义的行为。如果您不走运,这将破坏您的应用程序状态(因为它违反了仅在构造函数运行完成时才调用析构函数的规则——某些类类型可能依赖的规则)。
一个可能的解决方法(我没有测试过,但你可以)是:
static void noOpDeleter(ExternalRefCountData *self)
{
Q_UNUSED(self);
}
static inline QSharedPointer create()
{
typedef QtSharedPointer::ExternalRefCountWithContiguousData<T> Private;
typename Private::DestroyerFn noDestroy = &noOpDeleter;
typename Private::DestroyerFn destroy = &Private::deleter;
QSharedPointer result(Qt::Uninitialized);
result.d = Private::create(&result.value, noDestroy);
new (result.data()) T();
result.d->destroyer = destroy;
result.d->setQObjectShared(result.value, true);
result.enableSharedFromThis(result.data());
return result;
}
如果您可以验证上述内容,您应该可以随意将其编入补丁并将其提交给 Qt 错误跟踪器。希望附上一个工作补丁,他们会及时接受它。