P0135R1, copy elision and constant class objects

156 views
Skip to first unread message

Andrzej Krzemieński

unread,
Jul 8, 2016, 7:38:00 AM7/8/16
to ISO C++ Standard - Discussion
Hi Everyone,
It is my understanding that in the following direct initialization, where the destination object is const T and source object is (non-const) T, copy elision is disallowed:

T make_T();

const T t = make_T();
Right?

Does P0135R1 (Wording for guaranteed copy elision through simplified value categories) change this? Or do we still require a move constructor to be invoked in such case?

Regards,
&rzej;

Nicol Bolas

unread,
Jul 8, 2016, 9:06:27 AM7/8/16
to ISO C++ Standard - Discussion
On Friday, July 8, 2016 at 7:38:00 AM UTC-4, Andrzej Krzemieński wrote:
Hi Everyone,
It is my understanding that in the following direct initialization, where the destination object is const T and source object is (non-const) T, copy elision is disallowed:

What "direct initialization" are you talking about? The initialization of the `const T t` is copy initialization. As evidenced by the fact that you use an `=` sign. I highly doubt that guaranteed elision will transform copy initialization into direct initialization.

I think your question is whether initializing a const-qualified `T` permits guaranteed elision. I'm pretty sure that initializing a const-qualified `T` from a prvalue is a case for non-guaranteed elision, so I see no reason why they would add specialized wording that didn't allow it to be guaranteed.

Andrzej Krzemieński

unread,
Jul 8, 2016, 9:23:31 AM7/8/16
to ISO C++ Standard - Discussion


W dniu piątek, 8 lipca 2016 15:06:27 UTC+2 użytkownik Nicol Bolas napisał:
On Friday, July 8, 2016 at 7:38:00 AM UTC-4, Andrzej Krzemieński wrote:
Hi Everyone,
It is my understanding that in the following direct initialization, where the destination object is const T and source object is (non-const) T, copy elision is disallowed:

What "direct initialization" are you talking about? The initialization of the `const T t` is copy initialization. As evidenced by the fact that you use an `=` sign. I highly doubt that guaranteed elision will transform copy initialization into direct initialization.

My bad; I meant copy-initialization.
 

I think your question is whether initializing a const-qualified `T` permits guaranteed elision. I'm pretty sure that initializing a const-qualified `T` from a prvalue is a case for non-guaranteed elision, so I see no reason why they would add specialized wording that didn't allow it to be guaranteed.

Sorry, so many negatives, that I did not understand your reply.

It is my understanding that in C++14, compiler must not elide a copy-initialization of const T, because it might lose observable side effects of the constructor call: the standard does not allow copy elision in this case (only the as-if rule). Do you agree with this assertion about C++14?

Now, about C++17 (and P0135R1), my questions:
  1. Is copy elision guaranteed for copy-initialization of const T with T?
  2. Is copy elision even allowed (given that the constructor of T might have side effects)?

According to my interpretation, the answers to both questions are no and no: We must use a constructor, we must materialize the temporary. But I am not 100% sure.


Regards,

&rzej;

Nicol Bolas

unread,
Jul 8, 2016, 10:55:32 AM7/8/16
to ISO C++ Standard - Discussion


On Friday, July 8, 2016 at 9:23:31 AM UTC-4, Andrzej Krzemieński wrote:


W dniu piątek, 8 lipca 2016 15:06:27 UTC+2 użytkownik Nicol Bolas napisał:
On Friday, July 8, 2016 at 7:38:00 AM UTC-4, Andrzej Krzemieński wrote:
Hi Everyone,
It is my understanding that in the following direct initialization, where the destination object is const T and source object is (non-const) T, copy elision is disallowed:

What "direct initialization" are you talking about? The initialization of the `const T t` is copy initialization. As evidenced by the fact that you use an `=` sign. I highly doubt that guaranteed elision will transform copy initialization into direct initialization.

My bad; I meant copy-initialization.
 

I think your question is whether initializing a const-qualified `T` permits guaranteed elision. I'm pretty sure that initializing a const-qualified `T` from a prvalue is a case for non-guaranteed elision, so I see no reason why they would add specialized wording that didn't allow it to be guaranteed.

Sorry, so many negatives, that I did not understand your reply.

It is my understanding that in C++14, compiler must not elide a copy-initialization of const T, because it might lose observable side effects of the constructor call: the standard does not allow copy elision in this case (only the as-if rule).

Technically, all copy/move elision could have observable side-effects that will no longer happen if the compiler elides the copy/move. The standard is effectively saying under which circumstances that such side effects cannot be relied upon.

Do you agree with this assertion about C++14?

... Yes, but I was looking at N4582, the most recent C++ draft. This draft does not include any of P0135 in it, but it does say this:

when a temporary class object that has not been bound to a reference (12.2) would be copied/moved to a class object with the same type (ignoring cv-qualification), the copy/move operation can be omitted by constructing the temporary object directly into the target of the omitted copy/move

Whereas N4140 says this:

when a temporary class object that has not been bound to a reference (12.2) would be copied/moved to a class object with the same cv-unqualified type, the copy/move operation can be omitted by constructing the temporary object directly into the target of the omitted copy/move

So while C++14 does ship as you say, wording changes preceding guaranteed copy elision seem to permit elision in the case of a `const T` being initialized from a prvalue of type non-const `T`. I couldn't tell you if this was the result of a defect report or not. But I am sure that it had nothing to do with copy/move constructor side effects ;)

Note that cppreference.com gets the C++14-and-before wording wrong, using the post-C++14 wording in all cases.
 
Now, about C++17 (and P0135R1), my questions:
  1. Is copy elision guaranteed for copy-initialization of const T with T?
We don't have P0135R1, but the description from P0135R0 makes it clear that this ought to be allowed. Basically, P0135 says that prvalues don't make temporaries; the context in which they are used does. And the list of contexts which require a temporary does not include initializing a variable of the same base type with a different cv-qualifier.

So my reading of P0135R0 is that this would be allowed.
  1. Is copy elision even allowed (given that the constructor of T might have side effects)?
As previously stated, yes, regardless of P0135.

tong...@gmail.com

unread,
Jul 8, 2016, 12:41:02 PM7/8/16
to ISO C++ Standard - Discussion
On Friday, July 8, 2016 at 10:55:32 PM UTC+8, Nicol Bolas wrote:
... Yes, but I was looking at N4582, the most recent C++ draft. This draft does not include any of P0135 in it, but it does say this:

when a temporary class object that has not been bound to a reference (12.2) would be copied/moved to a class object with the same type (ignoring cv-qualification), the copy/move operation can be omitted by constructing the temporary object directly into the target of the omitted copy/move

Whereas N4140 says this:

when a temporary class object that has not been bound to a reference (12.2) would be copied/moved to a class object with the same cv-unqualified type, the copy/move operation can be omitted by constructing the temporary object directly into the target of the omitted copy/move

So while C++14 does ship as you say, wording changes preceding guaranteed copy elision seem to permit elision in the case of a `const T` being initialized from a prvalue of type non-const `T`. I couldn't tell you if this was the result of a defect report or not. But I am sure that it had nothing to do with copy/move constructor side effects ;)

Aren't "the same type (ignoring cv-qualification)" and "the same cv-unqualified type" just 2 ways to express the same thing? Note that the latter says cv-unqualified not cv-qualified.

I just tested g++/clang in c++14 mode and none of them do the copy, I guess the change in the wording you quoted is not for semantic but for clearness because people might misread unqualified as qualified.

T. C.

unread,
Jul 8, 2016, 3:01:42 PM7/8/16
to ISO C++ Standard - Discussion, tong...@gmail.com

The previous wording can be misread as requiring both types to be cv-unqualified.
Reply all
Reply to author
Forward
0 new messages