0

(I asked this question before but didn't give a viable example so I deleted previous one. I hope on this one I got the example right.)

Case:

#include <iostream>

struct S
{
    S() = default;

    S(const S &)
    {
        std::cout << "Copying" << std::endl;
    }

    S& operator=(const S &)
    {
        std::cout << "Copy assignment" << std::endl;
        return *this;
    }
};

int main()
{
    S s{};
    S s2{};
    S &ref = s;
    ref = s2;
}

As I understand, ref = s2; includes l2r conversion as it is a 'builtin direct assignment' that per cppreference expects an rvalue as its right argument.

I've read some of the SO questions regarding lvalue-to-rvalue conversion, but I'm still not sure if it involves copying of objects, and if it does, what kind of copying that is.

Let's say we're talking about class types.

From [conv.lval]/2:

Otherwise, if T has a class type, the conversion copy-initializes a temporary of type T from the glvalue and the result of the conversion is a prvalue for the temporary.

So, there is copy-initialization involved as a part of lvalue-to-rvalue conversion.

So taking an example of ref = s2;, with user-defined copy constructor that e.g. prints 'Copying', will that 'Copying' be printed during the execution of the aforementioned statement?

Well, obviously it won't. But that means I'm misunderstanding something here.

Is the copy-initialization during lvalue-to-rvalue conversion something like plain memcpy and not a copy-initialization in its full sense?

How all of this works? :)

ledonter
  • 1,269
  • 9
  • 27
  • 3
    The standard is not a good way to learn C++. I would recommend [one of the books](https://stackoverflow.com/q/388242/2069064) instead. In this case, `ref = s2` doesn't invoke the copy *constructor*, it invokes the copy *assignment operator*. – Barry Jan 29 '18 at 02:18
  • 1
    Learning C++ from the standard is a bit like learning law from reading court proceedings on reverse corporate mergers and the role in intellectual property discussions. It might give you some of the core concepts you need, but it will mostly confuse you and will at times be much too focused on currently irrelevant details for your taste. – Alex Huszagh Jan 29 '18 at 02:26
  • 2
    @Barry well, I've read practically all the Meyers and some Sutter as well :) and a dozen of SO question on l2r as well :) it does not make things easier in some cases though, so there _is_ a need to reach out to the standard :) I understand copy assignment operator is called, yes, I've updated the example: note that I have a ref taking copy assignment operator, but l2r still seems to apply; does that l2r perform a copy-initalization as written in the quote? It's a bit upsetting that everyone thinks you don't know anything about the lang unless you have a whole pack of SO rep on it :( – ledonter Jan 29 '18 at 02:30
  • 1
    @ledonter sigh. I'm trying to help you. If you want to infer from my comment that it comes from a source of malice and is perjorative solely based on your reputation on this site, that's entirely on you. – Barry Jan 29 '18 at 02:39
  • Possible duplicate of [lvalue to rvalue implicit conversion](https://stackoverflow.com/questions/20850536/lvalue-to-rvalue-implicit-conversion) – Cris Luengo Jan 29 '18 at 02:49

1 Answers1

2

As I understand, ref = s2; includes l2r conversion as it is a 'builtin direct assignment' that per cppreference expects and rvalue as its right argument.

Your mistake is in interpreting the assignment operator here is a built-in. It is not. The only types that have a built-in assignment operator are the fundamental types (pointers, char, int, etc.) What you have is a class type, which has an overloaded assignment operator (whether user-provided or implicitly generated by the compiler).

ref = s2; simply invokes S::operator=(S const&). It behaves as if you just typed ref.operator=(s2). There is no lvalue-to-rvalue conversion in that function's implementation, so no other copy is made. All that happens is that the line gets printed. No additional copy initialiation, etc.

If you implemented your assignment operator differently, as:

S& operator=(S /* no ref */) { return *this; }

Then an lvalue-to-rvalue conversion would happen in order actually invoke this function, and you would see your copy constructor get called.

Barry
  • 286,269
  • 29
  • 621
  • 977
  • *"It behaves as if you just typed `ref.operator=(s2)`"* except evaluation order, to be exact – Passer By Jan 29 '18 at 03:03
  • Hey @Barry. I have a question regarding your last part about "If you implemented your own assignment operator [...] Then an lvalue-to-rvalue conversion would happen". Why would this be the case? The argument of type S would be initialized using the copy ctor which again uses an lvalue reference as argument right? If this wouldn't be the case an lvalue of a normal class type that is passe by value to a function would undergo implicit l2r value conversion which isn't the case no? – ben Jun 03 '22 at 18:26