Move semantics in derived-to-base class conversionsWhat is move semantics?What is std::move(), and when should it be used?Move constructor on derived objectC++11 rvalues and move semantics confusion (return statement)Classes, Rvalues and Rvalue ReferencesWill member subobjects of local variables be moved too if returned from a function?lvalue to rvalue implicit conversionUnderstanding the code for std::move()Why are move semantics necessary to elide temporary copies?C++ move semantics - when to return an rvalue reference

How would someone destroy a black hole that’s at the centre of a planet?

Absconding a company after 1st day of joining

Can I activate an iPhone without an Apple ID?

How did John Lennon tune his guitar

Do native speakers use ZVE or CPU?

Why hasn't the U.S. government paid war reparations to any country it attacked?

Why does Hellboy file down his horns?

What is the English equivalent of 干物女 (dried fish woman)?

Verifying Hamiltonian Cycle solution in O(n^2), n is the length of the encoding of G

As a DM, how to avoid unconscious metagaming when dealing with a high AC character?

What impact would a dragon the size of Asia have on the environment?

Why limit to revolvers?

How to use "regular expression" to separate specific strings in Oracle

Hot object in a vacuum

What are some symbols representing peasants/oppressed persons fighting back?

Equivalent definitions of total angular momentum

How to fit a linear model in the Bayesian way in Mathematica?

Meaning of slash chord without anything left of the slash

Add region constraint to Graphics

Why do they not say "The Baby"

Can I capture stereo IQ signals from WebSDR?

Integral clarification

Deep Learning based time series forecasting

Redox reactions redefined



Move semantics in derived-to-base class conversions


What is move semantics?What is std::move(), and when should it be used?Move constructor on derived objectC++11 rvalues and move semantics confusion (return statement)Classes, Rvalues and Rvalue ReferencesWill member subobjects of local variables be moved too if returned from a function?lvalue to rvalue implicit conversionUnderstanding the code for std::move()Why are move semantics necessary to elide temporary copies?C++ move semantics - when to return an rvalue reference






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;








6















Consider the following class Buffer, which contains an std::vector object:



#include <vector>
#include <cstddef>

class Buffer
std::vector<std::byte> buf_;
protected:
Buffer(std::byte val): buf_(1024, val)
;


Now, consider the function make_zeroed_buffer() below. The class BufferBuilder is a local class that publicly derives from Buffer. Its purpose is to create Buffer objects.



Buffer make_zeroed_buffer() 
struct BufferBuilder: Buffer
BufferBuilder(): Buffer(std::byte0)
;

BufferBuilder buffer;

// ...

return buffer;



If no copy elision takes place, is the buffer object above guaranteed to be moved from?



My reasoning is the following:



  1. The expression buffer in the return statement is an lvalue. Since it is a local object that is not going to be used anymore, the compiler casts it into an rvalue.

  2. The buffer object is of type BufferBuilder. Buffer is a public base class of BufferBuilder, so this BufferBuilder object is implicitly converted into a Buffer object.

  3. This conversion, in turn, implies an implicit reference-to-derived to a reference-to-base conversion (i.e., a reference to BufferBuilder to a reference to Buffer). That reference to BufferBuilder is an rvalue reference (see 1.), which turns into an rvalue reference to Buffer.

  4. The rvalue reference to Buffer matches Buffer's move constructor, which is used to construct the Buffer object that make_zeroed_buffer() returns by value. As a result, the return value is constructed by moving from the Buffer part of the object buffer.









share|improve this question



















  • 2





    If no copy elision takes place What makes you think that this condition will ever be satisfied? From my recollection, when you explicitly return std::move(buffer); the compiler (clang) will issue a warning about surpressing copy elision.

    – Walter
    8 hours ago












  • @Walter What makes you think then that copy elision will always be satisfied?

    – El Profesor
    8 hours ago











  • If I remember well, in this very particular case you have to use return std::move(buffer)

    – Biagio Festa
    8 hours ago






  • 2





    No copy elision. The next statement is violated: In a return statement, when the operand is a prvalue of the same class type (ignoring cv-qualification) as the function return type

    – S.M.
    7 hours ago






  • 1





    The buffer object is of type BufferBuilder. Buffer is a public base class of BufferBuilder, so this BufferBuilder object is implicitly converted into a Buffer object. It is not true. The BufferBuilder object is copied implicitly to a Builder object. You confused with pointers to a derived class.

    – S.M.
    7 hours ago

















6















Consider the following class Buffer, which contains an std::vector object:



#include <vector>
#include <cstddef>

class Buffer
std::vector<std::byte> buf_;
protected:
Buffer(std::byte val): buf_(1024, val)
;


Now, consider the function make_zeroed_buffer() below. The class BufferBuilder is a local class that publicly derives from Buffer. Its purpose is to create Buffer objects.



Buffer make_zeroed_buffer() 
struct BufferBuilder: Buffer
BufferBuilder(): Buffer(std::byte0)
;

BufferBuilder buffer;

// ...

return buffer;



If no copy elision takes place, is the buffer object above guaranteed to be moved from?



My reasoning is the following:



  1. The expression buffer in the return statement is an lvalue. Since it is a local object that is not going to be used anymore, the compiler casts it into an rvalue.

  2. The buffer object is of type BufferBuilder. Buffer is a public base class of BufferBuilder, so this BufferBuilder object is implicitly converted into a Buffer object.

  3. This conversion, in turn, implies an implicit reference-to-derived to a reference-to-base conversion (i.e., a reference to BufferBuilder to a reference to Buffer). That reference to BufferBuilder is an rvalue reference (see 1.), which turns into an rvalue reference to Buffer.

  4. The rvalue reference to Buffer matches Buffer's move constructor, which is used to construct the Buffer object that make_zeroed_buffer() returns by value. As a result, the return value is constructed by moving from the Buffer part of the object buffer.









share|improve this question



















  • 2





    If no copy elision takes place What makes you think that this condition will ever be satisfied? From my recollection, when you explicitly return std::move(buffer); the compiler (clang) will issue a warning about surpressing copy elision.

    – Walter
    8 hours ago












  • @Walter What makes you think then that copy elision will always be satisfied?

    – El Profesor
    8 hours ago











  • If I remember well, in this very particular case you have to use return std::move(buffer)

    – Biagio Festa
    8 hours ago






  • 2





    No copy elision. The next statement is violated: In a return statement, when the operand is a prvalue of the same class type (ignoring cv-qualification) as the function return type

    – S.M.
    7 hours ago






  • 1





    The buffer object is of type BufferBuilder. Buffer is a public base class of BufferBuilder, so this BufferBuilder object is implicitly converted into a Buffer object. It is not true. The BufferBuilder object is copied implicitly to a Builder object. You confused with pointers to a derived class.

    – S.M.
    7 hours ago













6












6








6








Consider the following class Buffer, which contains an std::vector object:



#include <vector>
#include <cstddef>

class Buffer
std::vector<std::byte> buf_;
protected:
Buffer(std::byte val): buf_(1024, val)
;


Now, consider the function make_zeroed_buffer() below. The class BufferBuilder is a local class that publicly derives from Buffer. Its purpose is to create Buffer objects.



Buffer make_zeroed_buffer() 
struct BufferBuilder: Buffer
BufferBuilder(): Buffer(std::byte0)
;

BufferBuilder buffer;

// ...

return buffer;



If no copy elision takes place, is the buffer object above guaranteed to be moved from?



My reasoning is the following:



  1. The expression buffer in the return statement is an lvalue. Since it is a local object that is not going to be used anymore, the compiler casts it into an rvalue.

  2. The buffer object is of type BufferBuilder. Buffer is a public base class of BufferBuilder, so this BufferBuilder object is implicitly converted into a Buffer object.

  3. This conversion, in turn, implies an implicit reference-to-derived to a reference-to-base conversion (i.e., a reference to BufferBuilder to a reference to Buffer). That reference to BufferBuilder is an rvalue reference (see 1.), which turns into an rvalue reference to Buffer.

  4. The rvalue reference to Buffer matches Buffer's move constructor, which is used to construct the Buffer object that make_zeroed_buffer() returns by value. As a result, the return value is constructed by moving from the Buffer part of the object buffer.









share|improve this question
















Consider the following class Buffer, which contains an std::vector object:



#include <vector>
#include <cstddef>

class Buffer
std::vector<std::byte> buf_;
protected:
Buffer(std::byte val): buf_(1024, val)
;


Now, consider the function make_zeroed_buffer() below. The class BufferBuilder is a local class that publicly derives from Buffer. Its purpose is to create Buffer objects.



Buffer make_zeroed_buffer() 
struct BufferBuilder: Buffer
BufferBuilder(): Buffer(std::byte0)
;

BufferBuilder buffer;

// ...

return buffer;



If no copy elision takes place, is the buffer object above guaranteed to be moved from?



My reasoning is the following:



  1. The expression buffer in the return statement is an lvalue. Since it is a local object that is not going to be used anymore, the compiler casts it into an rvalue.

  2. The buffer object is of type BufferBuilder. Buffer is a public base class of BufferBuilder, so this BufferBuilder object is implicitly converted into a Buffer object.

  3. This conversion, in turn, implies an implicit reference-to-derived to a reference-to-base conversion (i.e., a reference to BufferBuilder to a reference to Buffer). That reference to BufferBuilder is an rvalue reference (see 1.), which turns into an rvalue reference to Buffer.

  4. The rvalue reference to Buffer matches Buffer's move constructor, which is used to construct the Buffer object that make_zeroed_buffer() returns by value. As a result, the return value is constructed by moving from the Buffer part of the object buffer.






c++ c++17 move-semantics derived-class object-slicing






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 6 hours ago









Christopher Oezbek

11.4k3 gold badges36 silver badges60 bronze badges




11.4k3 gold badges36 silver badges60 bronze badges










asked 8 hours ago









El ProfesorEl Profesor

11.3k3 gold badges27 silver badges42 bronze badges




11.3k3 gold badges27 silver badges42 bronze badges







  • 2





    If no copy elision takes place What makes you think that this condition will ever be satisfied? From my recollection, when you explicitly return std::move(buffer); the compiler (clang) will issue a warning about surpressing copy elision.

    – Walter
    8 hours ago












  • @Walter What makes you think then that copy elision will always be satisfied?

    – El Profesor
    8 hours ago











  • If I remember well, in this very particular case you have to use return std::move(buffer)

    – Biagio Festa
    8 hours ago






  • 2





    No copy elision. The next statement is violated: In a return statement, when the operand is a prvalue of the same class type (ignoring cv-qualification) as the function return type

    – S.M.
    7 hours ago






  • 1





    The buffer object is of type BufferBuilder. Buffer is a public base class of BufferBuilder, so this BufferBuilder object is implicitly converted into a Buffer object. It is not true. The BufferBuilder object is copied implicitly to a Builder object. You confused with pointers to a derived class.

    – S.M.
    7 hours ago












  • 2





    If no copy elision takes place What makes you think that this condition will ever be satisfied? From my recollection, when you explicitly return std::move(buffer); the compiler (clang) will issue a warning about surpressing copy elision.

    – Walter
    8 hours ago












  • @Walter What makes you think then that copy elision will always be satisfied?

    – El Profesor
    8 hours ago











  • If I remember well, in this very particular case you have to use return std::move(buffer)

    – Biagio Festa
    8 hours ago






  • 2





    No copy elision. The next statement is violated: In a return statement, when the operand is a prvalue of the same class type (ignoring cv-qualification) as the function return type

    – S.M.
    7 hours ago






  • 1





    The buffer object is of type BufferBuilder. Buffer is a public base class of BufferBuilder, so this BufferBuilder object is implicitly converted into a Buffer object. It is not true. The BufferBuilder object is copied implicitly to a Builder object. You confused with pointers to a derived class.

    – S.M.
    7 hours ago







2




2





If no copy elision takes place What makes you think that this condition will ever be satisfied? From my recollection, when you explicitly return std::move(buffer); the compiler (clang) will issue a warning about surpressing copy elision.

– Walter
8 hours ago






If no copy elision takes place What makes you think that this condition will ever be satisfied? From my recollection, when you explicitly return std::move(buffer); the compiler (clang) will issue a warning about surpressing copy elision.

– Walter
8 hours ago














@Walter What makes you think then that copy elision will always be satisfied?

– El Profesor
8 hours ago





@Walter What makes you think then that copy elision will always be satisfied?

– El Profesor
8 hours ago













If I remember well, in this very particular case you have to use return std::move(buffer)

– Biagio Festa
8 hours ago





If I remember well, in this very particular case you have to use return std::move(buffer)

– Biagio Festa
8 hours ago




2




2





No copy elision. The next statement is violated: In a return statement, when the operand is a prvalue of the same class type (ignoring cv-qualification) as the function return type

– S.M.
7 hours ago





No copy elision. The next statement is violated: In a return statement, when the operand is a prvalue of the same class type (ignoring cv-qualification) as the function return type

– S.M.
7 hours ago




1




1





The buffer object is of type BufferBuilder. Buffer is a public base class of BufferBuilder, so this BufferBuilder object is implicitly converted into a Buffer object. It is not true. The BufferBuilder object is copied implicitly to a Builder object. You confused with pointers to a derived class.

– S.M.
7 hours ago





The buffer object is of type BufferBuilder. Buffer is a public base class of BufferBuilder, so this BufferBuilder object is implicitly converted into a Buffer object. It is not true. The BufferBuilder object is copied implicitly to a Builder object. You confused with pointers to a derived class.

– S.M.
7 hours ago












2 Answers
2






active

oldest

votes


















5














RVO Optimisation




If no copy elision takes place [...]




Actually, copy elision will not take place (without if).



From C++ standard class.copy.elision#1:




is permitted in the following circumstances [...]:



-- in a return statement in a function with a class return type, when the expression is the name of a non-volatile automatic object ([...]) with the same type (ignoring cv-qualification) as the function return type [...]




Technically, when you return a derived class and a slicing operation takes place, the RVO cannot be applied.



Technically RVO works constructing the local object on the returning space on the stack frame.



|--------------|
| local vars |
|--------------|
| return addr |
|--------------|
| return obj |
|--------------|


Generally, a derived class can have a different memory layout than its parent (different size, alignments, ...). So there is no guarantee the local object (derived) can be constructed in the place reserved for the returned object (parent).




Implicit move



Now, what about implicit move?




is the buffer object above guaranteed to be moved from???




In short: no. On the contrary, it is guaranteed the object will be copied!



In this particular case implicit move will not be performed because of slicing.



In short, this happens because the overload resolution fails.
It tries to match against the move-constructor (Buffer::Buffer(Buffer&&)) whereas you have a BufferBuild object). So it fallbacks on the copy constructor.



From C++ standard class.copy.elision#3:




[...] if the type of the first parameter of the selected constructor or the return_­value overload is not an rvalue reference to the object's type (possibly cv-qualified), overload resolution is performed again, considering the object as an lvalue.




Therefore, since the first overload resolution fails (as I have said above), the expression will be treated as an lvalue (and not an rvalue), inhibiting the move.



An interesting talk by Arthur O'Dwyer specifically refers to this case. Youtube Video.




Additional Note



On clang, you can pass the flag -Wmove in order to detect this kind of problems.
Indeed for your code:



local variable 'buffer' will be copied despite being returned by name [-Wreturn-std-move]

return buffer;

^~~~~~

<source>:20:11: note: call 'std::move' explicitly to avoid copying

return buffer;


clang directly suggests you to use std::move on the return expression.






share|improve this answer




















  • 1





    In standardese, the implicit move is disallowed because "the type of the first parameter of the selected constructor (Buffer&&) is not an rvalue reference to the object's type (BufferBuilder&&)" eel.is/c++draft/class.copy.elision#3.sentence-2

    – Oktalist
    7 hours ago












  • Yeah, that what I've written (with other words). But thank you, maybe I can rephrase better and add a reference to the standard.

    – Biagio Festa
    7 hours ago











  • You phrased it fine, I just wanted to show the "proof".

    – Oktalist
    7 hours ago











  • If my reading of the spec is correct, this modification of the local class should make the compiler move it: struct BufferBuilder BufferBuilder():buffer(std::byte0) Buffer buffer; operator Buffer() && return (Buffer&&)buffer; ; Because there is no "selected constructor" anymore. (EDIT: needs a public constructor in Buffer :/)

    – Johannes Schaub - litb
    5 hours ago











  • Clang disagrees with my reading. GCC agrees. Clang says: "<source>:16:7: note: candidate function not viable: no known conversion from 'BufferBuilder' to 'BufferBuilder' for object argument operator Buffer() && return (Buffer&&)buffer; ". I think that this is a bug in Clang.

    – Johannes Schaub - litb
    4 hours ago



















-1














The object buffer from make_zeroed_buffer() will destroyed after will be made its copy with the help of Buffers' copy constructor for return value.






share|improve this answer








New contributor



zooorkin is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.





















    Your Answer






    StackExchange.ifUsing("editor", function ()
    StackExchange.using("externalEditor", function ()
    StackExchange.using("snippets", function ()
    StackExchange.snippets.init();
    );
    );
    , "code-snippets");

    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "1"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader:
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    ,
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );













    draft saved

    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f57028409%2fmove-semantics-in-derived-to-base-class-conversions%23new-answer', 'question_page');

    );

    Post as a guest















    Required, but never shown

























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    5














    RVO Optimisation




    If no copy elision takes place [...]




    Actually, copy elision will not take place (without if).



    From C++ standard class.copy.elision#1:




    is permitted in the following circumstances [...]:



    -- in a return statement in a function with a class return type, when the expression is the name of a non-volatile automatic object ([...]) with the same type (ignoring cv-qualification) as the function return type [...]




    Technically, when you return a derived class and a slicing operation takes place, the RVO cannot be applied.



    Technically RVO works constructing the local object on the returning space on the stack frame.



    |--------------|
    | local vars |
    |--------------|
    | return addr |
    |--------------|
    | return obj |
    |--------------|


    Generally, a derived class can have a different memory layout than its parent (different size, alignments, ...). So there is no guarantee the local object (derived) can be constructed in the place reserved for the returned object (parent).




    Implicit move



    Now, what about implicit move?




    is the buffer object above guaranteed to be moved from???




    In short: no. On the contrary, it is guaranteed the object will be copied!



    In this particular case implicit move will not be performed because of slicing.



    In short, this happens because the overload resolution fails.
    It tries to match against the move-constructor (Buffer::Buffer(Buffer&&)) whereas you have a BufferBuild object). So it fallbacks on the copy constructor.



    From C++ standard class.copy.elision#3:




    [...] if the type of the first parameter of the selected constructor or the return_­value overload is not an rvalue reference to the object's type (possibly cv-qualified), overload resolution is performed again, considering the object as an lvalue.




    Therefore, since the first overload resolution fails (as I have said above), the expression will be treated as an lvalue (and not an rvalue), inhibiting the move.



    An interesting talk by Arthur O'Dwyer specifically refers to this case. Youtube Video.




    Additional Note



    On clang, you can pass the flag -Wmove in order to detect this kind of problems.
    Indeed for your code:



    local variable 'buffer' will be copied despite being returned by name [-Wreturn-std-move]

    return buffer;

    ^~~~~~

    <source>:20:11: note: call 'std::move' explicitly to avoid copying

    return buffer;


    clang directly suggests you to use std::move on the return expression.






    share|improve this answer




















    • 1





      In standardese, the implicit move is disallowed because "the type of the first parameter of the selected constructor (Buffer&&) is not an rvalue reference to the object's type (BufferBuilder&&)" eel.is/c++draft/class.copy.elision#3.sentence-2

      – Oktalist
      7 hours ago












    • Yeah, that what I've written (with other words). But thank you, maybe I can rephrase better and add a reference to the standard.

      – Biagio Festa
      7 hours ago











    • You phrased it fine, I just wanted to show the "proof".

      – Oktalist
      7 hours ago











    • If my reading of the spec is correct, this modification of the local class should make the compiler move it: struct BufferBuilder BufferBuilder():buffer(std::byte0) Buffer buffer; operator Buffer() && return (Buffer&&)buffer; ; Because there is no "selected constructor" anymore. (EDIT: needs a public constructor in Buffer :/)

      – Johannes Schaub - litb
      5 hours ago











    • Clang disagrees with my reading. GCC agrees. Clang says: "<source>:16:7: note: candidate function not viable: no known conversion from 'BufferBuilder' to 'BufferBuilder' for object argument operator Buffer() && return (Buffer&&)buffer; ". I think that this is a bug in Clang.

      – Johannes Schaub - litb
      4 hours ago
















    5














    RVO Optimisation




    If no copy elision takes place [...]




    Actually, copy elision will not take place (without if).



    From C++ standard class.copy.elision#1:




    is permitted in the following circumstances [...]:



    -- in a return statement in a function with a class return type, when the expression is the name of a non-volatile automatic object ([...]) with the same type (ignoring cv-qualification) as the function return type [...]




    Technically, when you return a derived class and a slicing operation takes place, the RVO cannot be applied.



    Technically RVO works constructing the local object on the returning space on the stack frame.



    |--------------|
    | local vars |
    |--------------|
    | return addr |
    |--------------|
    | return obj |
    |--------------|


    Generally, a derived class can have a different memory layout than its parent (different size, alignments, ...). So there is no guarantee the local object (derived) can be constructed in the place reserved for the returned object (parent).




    Implicit move



    Now, what about implicit move?




    is the buffer object above guaranteed to be moved from???




    In short: no. On the contrary, it is guaranteed the object will be copied!



    In this particular case implicit move will not be performed because of slicing.



    In short, this happens because the overload resolution fails.
    It tries to match against the move-constructor (Buffer::Buffer(Buffer&&)) whereas you have a BufferBuild object). So it fallbacks on the copy constructor.



    From C++ standard class.copy.elision#3:




    [...] if the type of the first parameter of the selected constructor or the return_­value overload is not an rvalue reference to the object's type (possibly cv-qualified), overload resolution is performed again, considering the object as an lvalue.




    Therefore, since the first overload resolution fails (as I have said above), the expression will be treated as an lvalue (and not an rvalue), inhibiting the move.



    An interesting talk by Arthur O'Dwyer specifically refers to this case. Youtube Video.




    Additional Note



    On clang, you can pass the flag -Wmove in order to detect this kind of problems.
    Indeed for your code:



    local variable 'buffer' will be copied despite being returned by name [-Wreturn-std-move]

    return buffer;

    ^~~~~~

    <source>:20:11: note: call 'std::move' explicitly to avoid copying

    return buffer;


    clang directly suggests you to use std::move on the return expression.






    share|improve this answer




















    • 1





      In standardese, the implicit move is disallowed because "the type of the first parameter of the selected constructor (Buffer&&) is not an rvalue reference to the object's type (BufferBuilder&&)" eel.is/c++draft/class.copy.elision#3.sentence-2

      – Oktalist
      7 hours ago












    • Yeah, that what I've written (with other words). But thank you, maybe I can rephrase better and add a reference to the standard.

      – Biagio Festa
      7 hours ago











    • You phrased it fine, I just wanted to show the "proof".

      – Oktalist
      7 hours ago











    • If my reading of the spec is correct, this modification of the local class should make the compiler move it: struct BufferBuilder BufferBuilder():buffer(std::byte0) Buffer buffer; operator Buffer() && return (Buffer&&)buffer; ; Because there is no "selected constructor" anymore. (EDIT: needs a public constructor in Buffer :/)

      – Johannes Schaub - litb
      5 hours ago











    • Clang disagrees with my reading. GCC agrees. Clang says: "<source>:16:7: note: candidate function not viable: no known conversion from 'BufferBuilder' to 'BufferBuilder' for object argument operator Buffer() && return (Buffer&&)buffer; ". I think that this is a bug in Clang.

      – Johannes Schaub - litb
      4 hours ago














    5












    5








    5







    RVO Optimisation




    If no copy elision takes place [...]




    Actually, copy elision will not take place (without if).



    From C++ standard class.copy.elision#1:




    is permitted in the following circumstances [...]:



    -- in a return statement in a function with a class return type, when the expression is the name of a non-volatile automatic object ([...]) with the same type (ignoring cv-qualification) as the function return type [...]




    Technically, when you return a derived class and a slicing operation takes place, the RVO cannot be applied.



    Technically RVO works constructing the local object on the returning space on the stack frame.



    |--------------|
    | local vars |
    |--------------|
    | return addr |
    |--------------|
    | return obj |
    |--------------|


    Generally, a derived class can have a different memory layout than its parent (different size, alignments, ...). So there is no guarantee the local object (derived) can be constructed in the place reserved for the returned object (parent).




    Implicit move



    Now, what about implicit move?




    is the buffer object above guaranteed to be moved from???




    In short: no. On the contrary, it is guaranteed the object will be copied!



    In this particular case implicit move will not be performed because of slicing.



    In short, this happens because the overload resolution fails.
    It tries to match against the move-constructor (Buffer::Buffer(Buffer&&)) whereas you have a BufferBuild object). So it fallbacks on the copy constructor.



    From C++ standard class.copy.elision#3:




    [...] if the type of the first parameter of the selected constructor or the return_­value overload is not an rvalue reference to the object's type (possibly cv-qualified), overload resolution is performed again, considering the object as an lvalue.




    Therefore, since the first overload resolution fails (as I have said above), the expression will be treated as an lvalue (and not an rvalue), inhibiting the move.



    An interesting talk by Arthur O'Dwyer specifically refers to this case. Youtube Video.




    Additional Note



    On clang, you can pass the flag -Wmove in order to detect this kind of problems.
    Indeed for your code:



    local variable 'buffer' will be copied despite being returned by name [-Wreturn-std-move]

    return buffer;

    ^~~~~~

    <source>:20:11: note: call 'std::move' explicitly to avoid copying

    return buffer;


    clang directly suggests you to use std::move on the return expression.






    share|improve this answer















    RVO Optimisation




    If no copy elision takes place [...]




    Actually, copy elision will not take place (without if).



    From C++ standard class.copy.elision#1:




    is permitted in the following circumstances [...]:



    -- in a return statement in a function with a class return type, when the expression is the name of a non-volatile automatic object ([...]) with the same type (ignoring cv-qualification) as the function return type [...]




    Technically, when you return a derived class and a slicing operation takes place, the RVO cannot be applied.



    Technically RVO works constructing the local object on the returning space on the stack frame.



    |--------------|
    | local vars |
    |--------------|
    | return addr |
    |--------------|
    | return obj |
    |--------------|


    Generally, a derived class can have a different memory layout than its parent (different size, alignments, ...). So there is no guarantee the local object (derived) can be constructed in the place reserved for the returned object (parent).




    Implicit move



    Now, what about implicit move?




    is the buffer object above guaranteed to be moved from???




    In short: no. On the contrary, it is guaranteed the object will be copied!



    In this particular case implicit move will not be performed because of slicing.



    In short, this happens because the overload resolution fails.
    It tries to match against the move-constructor (Buffer::Buffer(Buffer&&)) whereas you have a BufferBuild object). So it fallbacks on the copy constructor.



    From C++ standard class.copy.elision#3:




    [...] if the type of the first parameter of the selected constructor or the return_­value overload is not an rvalue reference to the object's type (possibly cv-qualified), overload resolution is performed again, considering the object as an lvalue.




    Therefore, since the first overload resolution fails (as I have said above), the expression will be treated as an lvalue (and not an rvalue), inhibiting the move.



    An interesting talk by Arthur O'Dwyer specifically refers to this case. Youtube Video.




    Additional Note



    On clang, you can pass the flag -Wmove in order to detect this kind of problems.
    Indeed for your code:



    local variable 'buffer' will be copied despite being returned by name [-Wreturn-std-move]

    return buffer;

    ^~~~~~

    <source>:20:11: note: call 'std::move' explicitly to avoid copying

    return buffer;


    clang directly suggests you to use std::move on the return expression.







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited 7 hours ago

























    answered 7 hours ago









    Biagio FestaBiagio Festa

    5,9532 gold badges13 silver badges41 bronze badges




    5,9532 gold badges13 silver badges41 bronze badges







    • 1





      In standardese, the implicit move is disallowed because "the type of the first parameter of the selected constructor (Buffer&&) is not an rvalue reference to the object's type (BufferBuilder&&)" eel.is/c++draft/class.copy.elision#3.sentence-2

      – Oktalist
      7 hours ago












    • Yeah, that what I've written (with other words). But thank you, maybe I can rephrase better and add a reference to the standard.

      – Biagio Festa
      7 hours ago











    • You phrased it fine, I just wanted to show the "proof".

      – Oktalist
      7 hours ago











    • If my reading of the spec is correct, this modification of the local class should make the compiler move it: struct BufferBuilder BufferBuilder():buffer(std::byte0) Buffer buffer; operator Buffer() && return (Buffer&&)buffer; ; Because there is no "selected constructor" anymore. (EDIT: needs a public constructor in Buffer :/)

      – Johannes Schaub - litb
      5 hours ago











    • Clang disagrees with my reading. GCC agrees. Clang says: "<source>:16:7: note: candidate function not viable: no known conversion from 'BufferBuilder' to 'BufferBuilder' for object argument operator Buffer() && return (Buffer&&)buffer; ". I think that this is a bug in Clang.

      – Johannes Schaub - litb
      4 hours ago













    • 1





      In standardese, the implicit move is disallowed because "the type of the first parameter of the selected constructor (Buffer&&) is not an rvalue reference to the object's type (BufferBuilder&&)" eel.is/c++draft/class.copy.elision#3.sentence-2

      – Oktalist
      7 hours ago












    • Yeah, that what I've written (with other words). But thank you, maybe I can rephrase better and add a reference to the standard.

      – Biagio Festa
      7 hours ago











    • You phrased it fine, I just wanted to show the "proof".

      – Oktalist
      7 hours ago











    • If my reading of the spec is correct, this modification of the local class should make the compiler move it: struct BufferBuilder BufferBuilder():buffer(std::byte0) Buffer buffer; operator Buffer() && return (Buffer&&)buffer; ; Because there is no "selected constructor" anymore. (EDIT: needs a public constructor in Buffer :/)

      – Johannes Schaub - litb
      5 hours ago











    • Clang disagrees with my reading. GCC agrees. Clang says: "<source>:16:7: note: candidate function not viable: no known conversion from 'BufferBuilder' to 'BufferBuilder' for object argument operator Buffer() && return (Buffer&&)buffer; ". I think that this is a bug in Clang.

      – Johannes Schaub - litb
      4 hours ago








    1




    1





    In standardese, the implicit move is disallowed because "the type of the first parameter of the selected constructor (Buffer&&) is not an rvalue reference to the object's type (BufferBuilder&&)" eel.is/c++draft/class.copy.elision#3.sentence-2

    – Oktalist
    7 hours ago






    In standardese, the implicit move is disallowed because "the type of the first parameter of the selected constructor (Buffer&&) is not an rvalue reference to the object's type (BufferBuilder&&)" eel.is/c++draft/class.copy.elision#3.sentence-2

    – Oktalist
    7 hours ago














    Yeah, that what I've written (with other words). But thank you, maybe I can rephrase better and add a reference to the standard.

    – Biagio Festa
    7 hours ago





    Yeah, that what I've written (with other words). But thank you, maybe I can rephrase better and add a reference to the standard.

    – Biagio Festa
    7 hours ago













    You phrased it fine, I just wanted to show the "proof".

    – Oktalist
    7 hours ago





    You phrased it fine, I just wanted to show the "proof".

    – Oktalist
    7 hours ago













    If my reading of the spec is correct, this modification of the local class should make the compiler move it: struct BufferBuilder BufferBuilder():buffer(std::byte0) Buffer buffer; operator Buffer() && return (Buffer&&)buffer; ; Because there is no "selected constructor" anymore. (EDIT: needs a public constructor in Buffer :/)

    – Johannes Schaub - litb
    5 hours ago





    If my reading of the spec is correct, this modification of the local class should make the compiler move it: struct BufferBuilder BufferBuilder():buffer(std::byte0) Buffer buffer; operator Buffer() && return (Buffer&&)buffer; ; Because there is no "selected constructor" anymore. (EDIT: needs a public constructor in Buffer :/)

    – Johannes Schaub - litb
    5 hours ago













    Clang disagrees with my reading. GCC agrees. Clang says: "<source>:16:7: note: candidate function not viable: no known conversion from 'BufferBuilder' to 'BufferBuilder' for object argument operator Buffer() && return (Buffer&&)buffer; ". I think that this is a bug in Clang.

    – Johannes Schaub - litb
    4 hours ago






    Clang disagrees with my reading. GCC agrees. Clang says: "<source>:16:7: note: candidate function not viable: no known conversion from 'BufferBuilder' to 'BufferBuilder' for object argument operator Buffer() && return (Buffer&&)buffer; ". I think that this is a bug in Clang.

    – Johannes Schaub - litb
    4 hours ago














    -1














    The object buffer from make_zeroed_buffer() will destroyed after will be made its copy with the help of Buffers' copy constructor for return value.






    share|improve this answer








    New contributor



    zooorkin is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
    Check out our Code of Conduct.























      -1














      The object buffer from make_zeroed_buffer() will destroyed after will be made its copy with the help of Buffers' copy constructor for return value.






      share|improve this answer








      New contributor



      zooorkin is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.





















        -1












        -1








        -1







        The object buffer from make_zeroed_buffer() will destroyed after will be made its copy with the help of Buffers' copy constructor for return value.






        share|improve this answer








        New contributor



        zooorkin is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
        Check out our Code of Conduct.









        The object buffer from make_zeroed_buffer() will destroyed after will be made its copy with the help of Buffers' copy constructor for return value.







        share|improve this answer








        New contributor



        zooorkin is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
        Check out our Code of Conduct.








        share|improve this answer



        share|improve this answer






        New contributor



        zooorkin is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
        Check out our Code of Conduct.








        answered 8 hours ago









        zooorkinzooorkin

        1




        1




        New contributor



        zooorkin is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
        Check out our Code of Conduct.




        New contributor




        zooorkin is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
        Check out our Code of Conduct.





























            draft saved

            draft discarded
















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid


            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.

            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f57028409%2fmove-semantics-in-derived-to-base-class-conversions%23new-answer', 'question_page');

            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Canceling a color specificationRandomly assigning color to Graphics3D objects?Default color for Filling in Mathematica 9Coloring specific elements of sets with a prime modified order in an array plotHow to pick a color differing significantly from the colors already in a given color list?Detection of the text colorColor numbers based on their valueCan color schemes for use with ColorData include opacity specification?My dynamic color schemes

            Invision Community Contents History See also References External links Navigation menuProprietaryinvisioncommunity.comIPS Community ForumsIPS Community Forumsthis blog entry"License Changes, IP.Board 3.4, and the Future""Interview -- Matt Mecham of Ibforums""CEO Invision Power Board, Matt Mecham Is a Liar, Thief!"IPB License Explanation 1.3, 1.3.1, 2.0, and 2.1ArchivedSecurity Fixes, Updates And Enhancements For IPB 1.3.1Archived"New Demo Accounts - Invision Power Services"the original"New Default Skin"the original"Invision Power Board 3.0.0 and Applications Released"the original"Archived copy"the original"Perpetual licenses being done away with""Release Notes - Invision Power Services""Introducing: IPS Community Suite 4!"Invision Community Release Notes

            François Viète Contents Biography Work and thought Bibliography See also Notes Further reading External links Navigation menup. 21Google Bookspp. 75–77Google BooksDe thou (from University of Saint Andrews)ArchivedGoogle BooksGoogle BooksGoogle BooksGoogle booksGoogle Bookscc-parthenay.frL'histoire universelle (fr)Universal History (en)ArchivedAdsabs.harvard.eduPagesperso-orange.frArchive.orgChikara Sasaki. Descartes' mathematical thought p.259Google BooksGoogle BooksGoogle Bookspp. 152 and onwardGoogle BooksGoogle BooksScribd.comGoogle Books1257-7979Google BooksGoogle BooksGoogle BooksGoogle BooksGoogle BooksGoogle BooksGallica.bnf.frGoogle BooksGoogle Books"François Viète"Francois Viète: Father of Modern Algebraic NotationThe Lawyer and the GamblerAbout TarporleySite de Jean-Paul GuichardL'algèbre nouvelle"About the Harmonicon"cb120511976(data)1188044800000 0001 0913 5903n82164680ola2013766880073431702w6vt1sb70287374827140948071409480