In my app I have Q_INVOKABLE function that returns a naked pointer to a QObject owned by std::shared_ptr:
namespace tradeclient
{
class OrderModel : public QObject
{
Q_OBJECT
public:
Q_PROPERTY(QString marketId READ marketId CONSTANT)
Q_PROPERTY(quint64 id READ id CONSTANT)
signals:
void failed(qint64 code, QString message);
...
};
using OrderPtr = std::shared_ptr<OrderModel>;
class MarketModel : public QObject
{
Q_OBJECT
public:
Q_INVOKABLE tradeclient::OrderModel* createLimitOrder()
{
return m_orders.front().get();
}
private:
//In my app I initialize OrderModel-s and add them so some container and set C++ ownership.
std::vector<OrderPtr> m_orders;
};
} //namespace tradeclient
Q_DECLARE_METATYPE(tradeclient::OrderPtr)
and I am trying to invent a way to use std::shared_ptr from both C++ and QML.
I did various experimentation with Q_DECLARE_SMART_POINTER_METATYPE and came to the conclusion that is useless in my app because it does not expose wrapped object properties to QML.
As the next experiment I tried to declare a gadget containing std::shared_ptr as a member:
namespace tradeclient
{
class OrderGadget
{
Q_GADGET
Q_PROPERTY(tradeclient::OrderModel* p READ pointer);
public:
OrderGadget() = default;
OrderGadget(OrderPtr p) : m_p(std::move(p)) {}
private:
tradeclient::OrderModel* pointer()
{
return m_p.get();
}
OrderPtr m_p;
};
}
Q_DECLARE_METATYPE(tradeclient::OrderGadget)
return it from createLimitOrder() as follows:
namespace tradeclient
{
using OrderPtr = std::shared_ptr<OrderModel>;
class MarketModel : public QObject
{
Q_OBJECT
public:
Q_INVOKABLE tradeclient::OrderGadget createLimitOrder()
{
return m_orders.front();
}
private:
//Leave default ownership.
std::vector<OrderPtr> m_orders;
};
}
and access OrderModel object via p property in QML:
var shared_order = market.createLimitOrder()
var order = shared_order.p
if (order)
{
console.log("Qml", "Limit order type: %1, value: %2, id: %3".arg(typeof(order)).arg(JSON.stringify(order)).arg(order.marketId))
order.failed.connect((code, message) => { window.showFading("%1 order has failed: %2".arg(shared_order.p.marketId).arg(message))})
}
else
console.log("Qml", "The order is not defined.");
This QML code prints object properties:
Limit order type: object, value: {"objectName":"","marketId":"BTCUSDT","id":0,"side":0 ...
and connects to failed signal.
But it is not clear enough is this code correct. Is it possible that GC will delete order variable after the order object already destroyed by std::shared_ptr?
What is the lifetime of failed handler function that refers shared_order?