[Development] parented_ptr

Daniel Schürmann daschuer at mixxx.org
Fri Oct 31 23:47:49 CET 2025


Hi Marco

The main use case for me is this:

Before:
We store borrowed child pointers as member variables which would be bad 
practice without Qt, according to the C++ Core Guidelines.

After:
We have a standard way to annotate this case as a valid exception which 
gives readers and linters a hint about the ownership. It tells:
We rely o the destruction in the base class constructor and have taken 
care that no UB happens by a call into the destructed part of the parent.

 > I understand your proposal right it can dangle and is an alias to raw 
pointer

It is just a thin wrapper around the normal child members we see often 
in QObjects inherited classes. My intention is to not introduce any 
changes in the machine code except a null check during the constructor 
in Debug mode. Details needs to be discussed.

Before:
QDialog* m_pDialog;

After
QParentedPointer<QDialog> m_pDialog;

 > One problem with the life time by parent management is the deletion 
in the base QObect destructor. That leads to calls to half destructed 
objects with UB behavior.

QParentedPointer is not designed to fix this.

For my understanding the mentioned "half destructed objects" issue 
happens, because the inherited class makes the child, but the base class 
destroys it when the inherited part of the class is already destructed. 
By default it looks like as if only setParent_helper(null_ptr) uses the 
stored parent calling a base class parent function. I do not agree that 
this is already UB. This is well defined like any other function that is 
called form a destructor.

UB happens when data from the inherited object is touched. Does this 
already always happen?

For the cases where it happens you use Utils::UniqueObjectPtr which 
works universal, but is a bit expensive for always using it. For this 
particular case a std::unique_ptr would do the trick as well.
std::unique_ptr<QDialog> m_pDialog;

Does that make sense?

Best regards,

Daniel


Am 31.10.25 um 15:59 schrieb Marco Bubke:
> Hi Daniel, if I understand your proposal right it can dangle and is an 
> alias to raw pointer?
>
> In this thread you speak much about the implementation but not so much 
> what use cases it fixes and which it is not.
>
> One problem with the life time by parent management is the deletion in 
> the base QObect destructor. That leads to calls to half destructed 
> objects with UB behavior.
>
> I don't see how your proposal is fixing that. Should we even encourage 
> ownership by parent? I see the value for Q widgets but what about 
> other use cases.
>
>
> ------------------------------------------------------------------------
> *From:* Development <development-bounces at qt-project.org> on behalf of 
> Daniel Schürmann <daschuer at mixxx.org>
> *Sent:* Friday, October 31, 2025 15:28
> *To:* andre at familiesomers.nl <andre at familiesomers.nl>
> *Cc:* development at qt-project.org <development at qt-project.org>
> *Subject:* Re: [Development] parented_ptr
>> Hi,
>>
>> On 30-10-2025 18:20, Daniel Schürmann wrote:
>> >/Hi Marc and others />//>/> Just never create a child QObject w/o the final parent, and />/everything will be peachy. />//>/This is one of the drivers for initiative we can enforce with />/“makeChildObject()” and no  longer encouraged “new Object(this)”. />/> Every function that transfers ownership as a raw pointer is worth />/being replaced by one taking/returning by unique_ptr. Let the API />/enforce ownership transfer instead of letting the reader of the code />/guess. />//>/I agree. So we should encourage to use />/pParent->addChild(std::move(pChild)) instead of 
>> pChild->setParent(pParent) />//>/> I wouldn't even assert in the destructor. That will fire already />/when these things are held as member functions in the "wrong" order. />//>/I am as well against an ASSERT that may crashes the productive build />/for a semantical reason. What is the best pattern for Qt? />/How about issue a qWarning during the QParentedPointer *constructor* />/like we have in QObject::~QObject()? I have good experience with this. />//>/So, let me summarize the latest discussion, to verify if I got it 
>> right: />//>/We will introduce: /... in separate contributions...
>> >//>/1: Child* QObject::makeChildObject() />//>/with some template magic to automatically set the parent pointer and a />/static_assert for pParent == this otherwise /You would not need much magic, but sure. I can see a use case for this one.
>> >//>/2: QParentedPointer<Child> />//>/with a non-fatal warning or similar if the parent is null. Disallow />/copy and move, because for the borrowing case we want to use raw />/pointer or QPointer in line with the C++ core guideline. /
>> Wait... Disallow copy and move? I don't get what the point is then. You
>> say for the "borrowing case" we want raw pointers (fair enough), but
>> QParentedPointer itself already _is_ borrowed by definition, no? It is
>> conceptually owned by the parent the pointer is explicitly advertising
>> is set. What's the point of this thing if it's not copyable? It would
>> make their use very limited indeed, perhaps just used as private members
>> of a class containing some sub items or as temporary variables in a
>> function that sets up a dialog or something those lines.
>>
>> Could you explain more clearly why this thing cannot be copyable or movable?
>>
>> >/3: QObject::addChild(std::unique_ptr<QObject *> child) /...
>>
>> Cheers,
>>
>> André
>
> Hi André
>
> That's out of the dilemma that we want both a machine readable notation for
> parented pointers and following the C++ core guideline. I have no strong
> opinion here, I just want to give an advice how the QParentedPointer is
> meant to use (like I have used it in the past)
>
> What is clear for me is the normal borrowing case:
> voidOther::doSomethingWithThePointer(QObject* pObject); // does not not store
>
> And the weak reference case:
> voidOther::setPointerForLater(QPointer<QObject*> pObject); // allow to store, use after null check
>
> What I have read in this thread is that we don't want to change this
> recommendation and see QParentedPointer everywhere.
>   
> But where to borrow from? We don't have access to the original owned pointer
> inside the QObject. We can useQObject::children() to borrow all at once. Or
> as the usual practice make a second copy of the pointer in the inherited Object
> where we can "borrow" the already borrowed child pointer (Not recommended by
> the C++ Core Guidelines). Here comes the super-power of QParentedPointer in.
>
>
> classParent::QObject {
> ...
> QParentedPointer<Child> m_child; // <- It is allowed to store without QPointer, because its a reference to the pointer we own anyway.
> Child* m_child;  // this is ambiguous, because it can be a legacy owned object or a not allowed storage of a borrowed pointer. (don't use)
> }
>
> ..
> m_child = makeChildObject<Child>();
> ..
> m_other->doSomethingWithThePointer(m_child);
> Conclusion, we have no use case for copy a second QParentedPointer<Child> from m_child or move m_child out of Parent
> .
>
> Does that make sense?
>
> Best regards,
>
> Daniel
>
>
>
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.qt-project.org/pipermail/development/attachments/20251031/9bc53035/attachment-0001.htm>


More information about the Development mailing list