Thank you for all the thoughts. Here a summary:
std c++:
We have in std c++ these basic types:
int* pInt = new int() // the caller becomes the owner (legacy c++)
std::unique_ptr<int> pInt = std::make_unique<int>(); // the unique pointer
becomes the owner, no overhead.
std::shared_ptr<int> pInt = std::make_shared<int>(); // a hidden global
reference counting object becomes the actual owner. pInt is a strong
reference, for sharing that ownership.
c++ Core Guidlines:
gsl::owner<X*> res = new X{}; // Anotation for the legacy caller managed
ownership
Qt:
QObject* pObj = new QObject() // the caller becomes the owner (legacy c++)
QObject* pObj = new QObject(pParent) // the Qt Object tree becomes the
owner. The parent holds an invisible strong reference. Can be borrowed as
raw pointer or as as weak reference via QPointer.
Issue: No sematically diffrence between both cases!
pObj looks semantically as if the caller becomes the owner, as it would be
the case for non Qt c++.
This does not provide the clear ownership information the C++ Core Guidline
tries to enfore.
Discussion:
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#discussion-a-raw-pointer-or-reference-is-never-a-resource-handle
Case 1 Object without a parent:
gsl::owner<QObject*> pObj = new QObject() // the caller becomes the owner
(legacy c++)
Case 1 Object with a parent:
Translated to std c++ it would be samanically something like this:
std::unique_ptr<QObject> pUnique = std::make_unique<QObject>(pParent);
QObject* pObj = pUnique.data();
pParent->addChild(std::move(pUnique))
pObj is now semantically a borrowed pointers that is only valid for this
call and shall not be stored.
Following the C++ Core guidline, we need a resouce handle for storing it as
a member variable. Qt does not provide such handler.
This is the issue we need to fix.
For storing you may use a QPointer as a weak reference. You can borrow the
object via:
QObject* pObj = pQPointer.data();
if (pObj) {
... safe to use
Now consider that the pParent is "this"
pObj is still borrowed, but since the same object holds also a strong
reference there is the guarantee that it newer becomes dangling.
We can treat it like a strong reference, like the pUnique itself.
We have aloso discussed the UniqueObjectPtr() with the QPointer deleter, a
don't care solution that handles parented and not parented pointer in the
same way.
That does not fullfil the clear owenership smantics the C++ Core guidline
describes. The demand is however very valid. The QObject already has
refrence counting
in place but it does allows AFAIK only the weak refrences. A solution would
be to unlash the shared part of it like this.
std::unique_ptr<QObject> pShare = QSharedPointer(new QObject());
pParent->addChild(pShare);
And then extend QObjectPrivate::deleteChildren() to verify if a strong
reference exist before calling delete
Conclusion:
We need a new() wrapper for these four cases
QObject {
public:
QChild* createAndBorrowChild<QChild>()
QObject<QChild> createAndWeakRefChild<QChild>()
void addSharedChild(QPointer child);
protected:
QChildPointer<QChild> child = createChild<QChild>()
}
Ideas
* createAndBorrowChild: just a thin warpper around new for completenes
* createAndWeakRefChild(): has the chance to get rid of the inital double
allocation and refrence counting be creation all at once like in
std::make_shared.
* addSharedChild() for shared ownership
* createChild(): Creates a pointer which cant be copied or moved.
What do you think? Has this a chance been integrated to QT?
Best regards,
Daniel
--
Development mailing list
[email protected]
https://lists.qt-project.org/listinfo/development