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

Reply via email to