> On 20 May 2019, at 20:18, Mutz, Marc via Development 
> <development@qt-project.org> wrote:
> 
> On 2019-05-20 17:16, Thiago Macieira wrote:
>> On Monday, 20 May 2019 05:51:49 PDT Mutz, Marc via Development wrote:
>>> Or maybe we don't disagree at all and Thiago would accept allocating
>>> memory (or, by extension, anything that's noexcept(false)) as a very
>>> good reason to have a nullptr d?
>> I hadn't thought of noexcept, but let's be clear: yes, move constructors must
>> be noexcept. That might be the good reason why it can't reset to a valid
>> state.
> 
> What a feat it would be if Qt celebrated the 10th anniversary of the 
> publication of Elements of Programming with embracing the partially-formed 
> state :)
> 
> So, we seem to agree that moved-from objects may have d == nullptr. In the 
> following, let this be our premiss.

I fully agree with this/
> 
> Where we still, maybe, disagree, is whether d == nullptr is a valid state. 
> The difference is whether member functions other then destruction and 
> assignment check for a nullptr d. I'd propose that on classes under the above 
> premiss, Q_D contains Q_ASSERT(d). This, I think, strikes the best balance 
> between safety and speed. I think it's important to make using moved-from 
> objects an error, because it is. Trying to pamper it over by assigning some 
> magic meaning to a nullptr d is going to cause more problems than it solves 
> (std::variant::valueless_by_exception, anyone?).

If the default constructed object has a pointer to a shared_null or similar, I 
agree that Q_ASSERT(d) is the best option. But I’d like to question that. IMO 
we should reconsider that and change the default constructor to also set d to a 
nullptr.
> 
> If and when we accept this as policy going forward, the next question 
> becomes: What does the default ctor do? I fully realize that after decades of 
> constructing magic values at default construction time, Qt is in no position 
> to make default constructors set d = nullptr.

Why? I see no reason why we couldn’t do this and stay 100% source compatible. 
Yes, it would require checking d for nullptr in all methods, but I don’t think 
that’s costing a lot. And we gain something because default constructed objects 
don’t require a relocation to find the shared_null.

> For existing classes, the documented behaviour of the default constructor is 
> to establish a particular state (cf. QPen). But at least for new classes, we 
> should really think about having the default ctor do nothing more than d = 
> nullptr. And maybe deprecate the default constructor's value for Qt 7 or 8.

Agree with new classes, but as said above, I think we should strongly consider 
doing this for existing classes as well.
> 
> Why is a almost-no-op default ctor so important? Performance, yes. Noexcept, 
> yes. And there's need for this. Grep Qt::Initialization. People _need_ the 
> default ctors to do less work. Let's give it to them.

Fully agree here.
> 
> But I'd like to focus on something else here: Qt likes to pride itself for 
> good API design. So let's look at it from that angle:
> 
>   QPen pen1 = ~~~;
>   QPen pen2 = std::move(pen1);
>   QPen pen3;
> 
> What's the state of 'pen1' now? Well, QPen is actually a class that sets d = 
> nullptr in the moved-from object. So pen1 does not represent a value. This 
> behaviour is in Qt for ten(!) minor releases now. I didn't find a bugreport 
> about that. What about pen3? Well, black, solid, width=1 pen. Why do I know? 
> Because I looked it up. It makes the code hard to understand, because for 
> each class, you need to know what the default constructor does. Worse: We 
> don't know what the intent of the developer is here. Does she want to create 
> (a) a black pen, or does she (b) simply want to have _a_ pen, so she can 
> specify later what it should be? We don't know. We need to scan the code 
> further.

Having the default constructor set d to a nullptr nicely solves that. Pen1 and 
pen3 will have the same state, namely the one you get with a default 
constructor.

Cheers,
Lars

> 
> What is striking here is that a moved-from pen is _different_ than a 
> default-constructed one. Wouldn't it be ore intuitive if the states were the 
> same?
> 
> Under Stepanov's model
> 
>   QPen pen1 = Qt::black; // clearly (a)
>   QPen pen2;             // clearly (b)
> 
> it's 100% clear that pen2 is just there to be assigned to later. So, (b). It 
> cannot possibly be (a), because a default-constructed QPen object does not 
> represent a valid pen. Furthermore, when pen1 is moved from, it will end up 
> in the same state as pen2 - partially-formed.
> 
> Can it get any simpler?
> 
> Thanks,
> Marc
> _______________________________________________
> Development mailing list
> Development@qt-project.org
> https://lists.qt-project.org/listinfo/development

_______________________________________________
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development

Reply via email to