Dường như bạn đã tìm thấy lỗi trong Qt. Tôi đề nghị quý vị nộp một báo cáo lỗi và tài liệu tham khảo này lỗi phần nào liên quan: https://bugreports.qt.io/browse/QTBUG-14637
Vấn đề có vẻ là trong http://code.qt.io/cgit/qt/qtbase.git/tree/src/corelib/tools/qsharedpointer_impl.h?h=v5.5.1#n420 - mà đơn giản hóa mã trông như thế này:
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;
}
Đó là một chút phức tạp với tham chiếu đến các chức năng khác (chủ yếu trong cùng một tệp), nhưng có vẻ như deleter
được lưu trữ trong result
trước khi hàm tạo được gọi theo vị trí new
. Khi constructor của bạn ném, đối tượng của bạn chưa bao giờ được xây dựng hoàn chỉnh, nhưng QSharedPointer result
đã được xây dựng và chứa deleter. Từ đó, chỉ cần một bước nhảy ngắn đến hàm deleter
:
static void deleter(ExternalRefCountData *self)
{
ExternalRefCountWithContiguousData *that =
static_cast<ExternalRefCountWithContiguousData *>(self);
that->data.~T();
}
Và giờ đây hàm hủy của bạn được gọi, mặc dù hàm tạo của bạn chưa bao giờ hoàn thành. Đó là hành vi không xác định. Nếu bạn không may mắn, điều này sẽ làm hỏng trạng thái ứng dụng của bạn (vì nó đi ngược lại quy tắc mà một destructor chỉ được gọi nếu một hàm tạo chạy đến hoàn thành - một quy tắc mà một số kiểu lớp có thể dựa vào).
Một sửa chữa càng tốt (mà tôi đã không kiểm tra, nhưng bạn có thể) là:
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;
}
Nếu bạn có thể xác nhận ở trên, bạn nên cảm thấy tự do để dệt nó thành một bản vá và nộp cho Trình theo dõi lỗi Qt. Hy vọng rằng với một miếng vá làm việc kèm theo họ sẽ chấp nhận nó kịp thời.
Nguồn
2015-12-15 14:51:13
Để tham chiếu mã nguồn cho phiên bản 'QSharedPointer :: create() cụ thể của bạn là ở đây: http://code.qt.io/cgit/qt/qtbase.git/tree/src/corelib/tools/ qsharedpointer_impl.h? h = v5.5.1 # n420 - Tôi cho rằng bạn đang xây dựng mà không có 'QT_SHAREDPOINTER_TRACK_POINTERS' được xác định? –
Và đây là lỗi Qt có thể liên quan được đệ trình năm năm trước (không có hoạt động nào kể từ đó): https://bugreports.qt.io/browse/QTBUG-14637 –
@JohnZwinck Có, nó không được xác định. Khi tôi hiểu lá cờ này được sử dụng để gỡ lỗi nhiều con trỏ thông minh sở hữu cùng một đối tượng. Hoặc tôi có nên thử không? – Yrchgrchh