Why does moving std::optional not reset state

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP











up vote
17
down vote

favorite
3












I was rather surprised to learn that the move constructor (and assignment for that matter) of std::optional does not reset the optional moved from, as can be seen in [19.6.3.1/7] which states "bool(rhs) is unchanged."



This can also be seen by the following code:



#include <ios>
#include <iostream>
#include <optional>
#include <utility>

int main()
std::optional<int> foo 0 ;
std::optional<int> bar std::move(foo) ;

std::cout << std::boolalpha
<< foo.has_value() << 'n' // true
<< bar.has_value() << 'n'; // true



This seems to contradict other instances of moving in the standard library such as with std::vector where the container moved from is usually reset in some way (in vector's case it is guaranteed to be empty afterwards) to "invalidate" it even if the objects contained within it themselves have been moved from already. Is there any reason for this or potential use case this decision is supposed to support such as perhaps trying to mimic the behavior of a non-optional version of the same type?







share|improve this question






















  • Mainly explained in the documentation: en.cppreference.com/w/cpp/utility/move
    – Phil1970
    Aug 12 at 2:18






  • 6




    "in vector's case it is guaranteed to be empty afterwards" Um... no it isn't.
    – Nicol Bolas
    Aug 12 at 4:42






  • 1




    @NicolBolas Well in most cases, cppreference at least says that the "After the move, other is guaranteed to be empty().", but in the case of using a custom allocator such is not true (but I wasn't talking about using a custom allocator so while technically correct that's not really what I meant).
    – Lemon Drop
    Aug 12 at 14:58






  • 2




    @LemonDrop: Well then cppreference is lying. The standard does not say that, and the standard is what matters.
    – Nicol Bolas
    Aug 12 at 15:01






  • 2




    On the state of a moved-from vector: stackoverflow.com/a/17735913/576911
    – Howard Hinnant
    Aug 13 at 1:25














up vote
17
down vote

favorite
3












I was rather surprised to learn that the move constructor (and assignment for that matter) of std::optional does not reset the optional moved from, as can be seen in [19.6.3.1/7] which states "bool(rhs) is unchanged."



This can also be seen by the following code:



#include <ios>
#include <iostream>
#include <optional>
#include <utility>

int main()
std::optional<int> foo 0 ;
std::optional<int> bar std::move(foo) ;

std::cout << std::boolalpha
<< foo.has_value() << 'n' // true
<< bar.has_value() << 'n'; // true



This seems to contradict other instances of moving in the standard library such as with std::vector where the container moved from is usually reset in some way (in vector's case it is guaranteed to be empty afterwards) to "invalidate" it even if the objects contained within it themselves have been moved from already. Is there any reason for this or potential use case this decision is supposed to support such as perhaps trying to mimic the behavior of a non-optional version of the same type?







share|improve this question






















  • Mainly explained in the documentation: en.cppreference.com/w/cpp/utility/move
    – Phil1970
    Aug 12 at 2:18






  • 6




    "in vector's case it is guaranteed to be empty afterwards" Um... no it isn't.
    – Nicol Bolas
    Aug 12 at 4:42






  • 1




    @NicolBolas Well in most cases, cppreference at least says that the "After the move, other is guaranteed to be empty().", but in the case of using a custom allocator such is not true (but I wasn't talking about using a custom allocator so while technically correct that's not really what I meant).
    – Lemon Drop
    Aug 12 at 14:58






  • 2




    @LemonDrop: Well then cppreference is lying. The standard does not say that, and the standard is what matters.
    – Nicol Bolas
    Aug 12 at 15:01






  • 2




    On the state of a moved-from vector: stackoverflow.com/a/17735913/576911
    – Howard Hinnant
    Aug 13 at 1:25












up vote
17
down vote

favorite
3









up vote
17
down vote

favorite
3






3





I was rather surprised to learn that the move constructor (and assignment for that matter) of std::optional does not reset the optional moved from, as can be seen in [19.6.3.1/7] which states "bool(rhs) is unchanged."



This can also be seen by the following code:



#include <ios>
#include <iostream>
#include <optional>
#include <utility>

int main()
std::optional<int> foo 0 ;
std::optional<int> bar std::move(foo) ;

std::cout << std::boolalpha
<< foo.has_value() << 'n' // true
<< bar.has_value() << 'n'; // true



This seems to contradict other instances of moving in the standard library such as with std::vector where the container moved from is usually reset in some way (in vector's case it is guaranteed to be empty afterwards) to "invalidate" it even if the objects contained within it themselves have been moved from already. Is there any reason for this or potential use case this decision is supposed to support such as perhaps trying to mimic the behavior of a non-optional version of the same type?







share|improve this question














I was rather surprised to learn that the move constructor (and assignment for that matter) of std::optional does not reset the optional moved from, as can be seen in [19.6.3.1/7] which states "bool(rhs) is unchanged."



This can also be seen by the following code:



#include <ios>
#include <iostream>
#include <optional>
#include <utility>

int main()
std::optional<int> foo 0 ;
std::optional<int> bar std::move(foo) ;

std::cout << std::boolalpha
<< foo.has_value() << 'n' // true
<< bar.has_value() << 'n'; // true



This seems to contradict other instances of moving in the standard library such as with std::vector where the container moved from is usually reset in some way (in vector's case it is guaranteed to be empty afterwards) to "invalidate" it even if the objects contained within it themselves have been moved from already. Is there any reason for this or potential use case this decision is supposed to support such as perhaps trying to mimic the behavior of a non-optional version of the same type?









share|improve this question













share|improve this question




share|improve this question








edited Aug 12 at 4:46









Nicol Bolas

272k32443609




272k32443609










asked Aug 12 at 1:42









Lemon Drop

1,27011029




1,27011029











  • Mainly explained in the documentation: en.cppreference.com/w/cpp/utility/move
    – Phil1970
    Aug 12 at 2:18






  • 6




    "in vector's case it is guaranteed to be empty afterwards" Um... no it isn't.
    – Nicol Bolas
    Aug 12 at 4:42






  • 1




    @NicolBolas Well in most cases, cppreference at least says that the "After the move, other is guaranteed to be empty().", but in the case of using a custom allocator such is not true (but I wasn't talking about using a custom allocator so while technically correct that's not really what I meant).
    – Lemon Drop
    Aug 12 at 14:58






  • 2




    @LemonDrop: Well then cppreference is lying. The standard does not say that, and the standard is what matters.
    – Nicol Bolas
    Aug 12 at 15:01






  • 2




    On the state of a moved-from vector: stackoverflow.com/a/17735913/576911
    – Howard Hinnant
    Aug 13 at 1:25
















  • Mainly explained in the documentation: en.cppreference.com/w/cpp/utility/move
    – Phil1970
    Aug 12 at 2:18






  • 6




    "in vector's case it is guaranteed to be empty afterwards" Um... no it isn't.
    – Nicol Bolas
    Aug 12 at 4:42






  • 1




    @NicolBolas Well in most cases, cppreference at least says that the "After the move, other is guaranteed to be empty().", but in the case of using a custom allocator such is not true (but I wasn't talking about using a custom allocator so while technically correct that's not really what I meant).
    – Lemon Drop
    Aug 12 at 14:58






  • 2




    @LemonDrop: Well then cppreference is lying. The standard does not say that, and the standard is what matters.
    – Nicol Bolas
    Aug 12 at 15:01






  • 2




    On the state of a moved-from vector: stackoverflow.com/a/17735913/576911
    – Howard Hinnant
    Aug 13 at 1:25















Mainly explained in the documentation: en.cppreference.com/w/cpp/utility/move
– Phil1970
Aug 12 at 2:18




Mainly explained in the documentation: en.cppreference.com/w/cpp/utility/move
– Phil1970
Aug 12 at 2:18




6




6




"in vector's case it is guaranteed to be empty afterwards" Um... no it isn't.
– Nicol Bolas
Aug 12 at 4:42




"in vector's case it is guaranteed to be empty afterwards" Um... no it isn't.
– Nicol Bolas
Aug 12 at 4:42




1




1




@NicolBolas Well in most cases, cppreference at least says that the "After the move, other is guaranteed to be empty().", but in the case of using a custom allocator such is not true (but I wasn't talking about using a custom allocator so while technically correct that's not really what I meant).
– Lemon Drop
Aug 12 at 14:58




@NicolBolas Well in most cases, cppreference at least says that the "After the move, other is guaranteed to be empty().", but in the case of using a custom allocator such is not true (but I wasn't talking about using a custom allocator so while technically correct that's not really what I meant).
– Lemon Drop
Aug 12 at 14:58




2




2




@LemonDrop: Well then cppreference is lying. The standard does not say that, and the standard is what matters.
– Nicol Bolas
Aug 12 at 15:01




@LemonDrop: Well then cppreference is lying. The standard does not say that, and the standard is what matters.
– Nicol Bolas
Aug 12 at 15:01




2




2




On the state of a moved-from vector: stackoverflow.com/a/17735913/576911
– Howard Hinnant
Aug 13 at 1:25




On the state of a moved-from vector: stackoverflow.com/a/17735913/576911
– Howard Hinnant
Aug 13 at 1:25












4 Answers
4






active

oldest

votes

















up vote
30
down vote



accepted










Unless otherwise specified, a moved-from object of class type is left in a valid but unspecified state. Not necessarily a "reset state", and definitely not "invalidated".



For primitive types , moving is the same as copying, i.e. the source is unchanged.



The defaulted move-constructor for a class type with primitive members will move each member, i.e. leave the primitive members unchanged; a user-defined move constructor might or might not "reset" them.



A moved-from vector may or may not still have elements in it. We would expect it not to, since that's efficient, but it cannot be relied on.



A moved-from std::string may still have elements in it, because of Small String Optimization.




move on std::optional is actually specified by the standard (C++17 [optional.ctor]/7). It is defined as doing move on the contained type, if present. It does not turn a valued optional into a valueless optional.



So it is actually expected that your code outputs true true, and the actual contained value in foo should stay the same too.




Regarding the question of why std::optional 's move-constructor is defined this way: I can't say for sure; but an optional is not like a vector with max size of 1. It's more like a variable with a validity flag tacked on. Accordingly, it makes sense for moving an optional to be like moving the variable.



If moving an optional left the old one "empty", then a = std::move(b); would invoke the destructor of b's managed object, which would be unexpected (to me, at least).






share|improve this answer





























    up vote
    17
    down vote













    In a word: Performance.



    One of the chief motivating reasons for move semantics to exist in the first place is performance. So the special operations move construction and move assignment should be as fast as possible for all types.



    In order to assist this goal, it is standard practice that moved-from objects be left in a valid but unspecified state. So the very minimum that optional move construction/assignment need to do is to move from the source argument. To specify setting the source to not have a value after the move is equivalent to saying:




    After you move, do some extra, unnecessary work.




    No matter how small that extra work is, it is non-zero. Some (and I dare say many) clients will not need that extra work, and should not have to pay for it. Clients who do need it can easily add x.reset() after the move, putting the moved-from optional into a well-specified state.






    share|improve this answer






















    • Problem is that most(all?) std implementations do the wrong thing with std::string so they give unreasonable expectations to users. :/
      – NoSenseEtAl
      Aug 18 at 10:14











    • @NoSenseEtAl: I can only speak for the libc++ std::string. It does indeed leave a moved-from string empty, but not because it is "wrong", but because that is the fastest thing for this design. The libc++ string was actually designed from the move members outward. It copies all of the bits of the string object, and then zeros all of the bits of the source string object. It does not check whether the string is long or short. This copy&zero algorithm is correct whether the string is in the long or short mode. It would be incorrect to avoid the zero when in the long mode.
      – Howard Hinnant
      Aug 18 at 13:41










    • I find it weird that it is faster, since anyway destination string will need to branch on long or short because it needs to know if it is storing pointers or internal buffer, but I trust you. :)
      – NoSenseEtAl
      Aug 19 at 3:44







    • 1




      Another nice thing about libc++ is that its source is so easily inspectable. ;-) github.com/llvm-mirror/libcxx/blob/master/include/…
      – Howard Hinnant
      Aug 19 at 13:42










    • well github has bad code navigation, but anyways you would need benchmarks, not just the source, but like I said I believe you, since I assume you did them when you implemented string rvr ctor. :)
      – NoSenseEtAl
      Aug 19 at 14:23

















    up vote
    4
    down vote













    What that paragraph says is that if that optional had a value, it still has a value. Since that value has been moved from (to the newly constructed object), it could be a different value than what it had before the move. This allows you to access the moved-from optional object the same way as a moved-from non-optional object, so the behavior of a T vs. optional<T> (when it contains an object) when accessed after the move is the same.



    Also, the overall effect of a move from an optional depends on how the contained type T handles a move. Other classes (like vector) do not have this dependency.






    share|improve this answer



























      up vote
      2
      down vote













      While it might be reasonable to expect that std::optonal behaves similar to std::unique_ptr which resets state of moved-from object, there are reasons not to demand such behavior. I think one of them is that std::optional of a trivial type should be a trivially copyable type. As such it cannot have non-defaulted move constructor and cannot reset has_value flag.



      Having std::optional for a non-trivial type behave differently from optional for a trivial type is a rather bad idea.






      share|improve this answer




















        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',
        convertImagesToLinks: true,
        noModals: false,
        showLowRepImageUploadWarning: true,
        reputationToPostImages: 10,
        bindNavPrevention: true,
        postfix: "",
        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%2f51805059%2fwhy-does-moving-stdoptional-not-reset-state%23new-answer', 'question_page');

        );

        Post as a guest






























        4 Answers
        4






        active

        oldest

        votes








        4 Answers
        4






        active

        oldest

        votes









        active

        oldest

        votes






        active

        oldest

        votes








        up vote
        30
        down vote



        accepted










        Unless otherwise specified, a moved-from object of class type is left in a valid but unspecified state. Not necessarily a "reset state", and definitely not "invalidated".



        For primitive types , moving is the same as copying, i.e. the source is unchanged.



        The defaulted move-constructor for a class type with primitive members will move each member, i.e. leave the primitive members unchanged; a user-defined move constructor might or might not "reset" them.



        A moved-from vector may or may not still have elements in it. We would expect it not to, since that's efficient, but it cannot be relied on.



        A moved-from std::string may still have elements in it, because of Small String Optimization.




        move on std::optional is actually specified by the standard (C++17 [optional.ctor]/7). It is defined as doing move on the contained type, if present. It does not turn a valued optional into a valueless optional.



        So it is actually expected that your code outputs true true, and the actual contained value in foo should stay the same too.




        Regarding the question of why std::optional 's move-constructor is defined this way: I can't say for sure; but an optional is not like a vector with max size of 1. It's more like a variable with a validity flag tacked on. Accordingly, it makes sense for moving an optional to be like moving the variable.



        If moving an optional left the old one "empty", then a = std::move(b); would invoke the destructor of b's managed object, which would be unexpected (to me, at least).






        share|improve this answer


























          up vote
          30
          down vote



          accepted










          Unless otherwise specified, a moved-from object of class type is left in a valid but unspecified state. Not necessarily a "reset state", and definitely not "invalidated".



          For primitive types , moving is the same as copying, i.e. the source is unchanged.



          The defaulted move-constructor for a class type with primitive members will move each member, i.e. leave the primitive members unchanged; a user-defined move constructor might or might not "reset" them.



          A moved-from vector may or may not still have elements in it. We would expect it not to, since that's efficient, but it cannot be relied on.



          A moved-from std::string may still have elements in it, because of Small String Optimization.




          move on std::optional is actually specified by the standard (C++17 [optional.ctor]/7). It is defined as doing move on the contained type, if present. It does not turn a valued optional into a valueless optional.



          So it is actually expected that your code outputs true true, and the actual contained value in foo should stay the same too.




          Regarding the question of why std::optional 's move-constructor is defined this way: I can't say for sure; but an optional is not like a vector with max size of 1. It's more like a variable with a validity flag tacked on. Accordingly, it makes sense for moving an optional to be like moving the variable.



          If moving an optional left the old one "empty", then a = std::move(b); would invoke the destructor of b's managed object, which would be unexpected (to me, at least).






          share|improve this answer
























            up vote
            30
            down vote



            accepted







            up vote
            30
            down vote



            accepted






            Unless otherwise specified, a moved-from object of class type is left in a valid but unspecified state. Not necessarily a "reset state", and definitely not "invalidated".



            For primitive types , moving is the same as copying, i.e. the source is unchanged.



            The defaulted move-constructor for a class type with primitive members will move each member, i.e. leave the primitive members unchanged; a user-defined move constructor might or might not "reset" them.



            A moved-from vector may or may not still have elements in it. We would expect it not to, since that's efficient, but it cannot be relied on.



            A moved-from std::string may still have elements in it, because of Small String Optimization.




            move on std::optional is actually specified by the standard (C++17 [optional.ctor]/7). It is defined as doing move on the contained type, if present. It does not turn a valued optional into a valueless optional.



            So it is actually expected that your code outputs true true, and the actual contained value in foo should stay the same too.




            Regarding the question of why std::optional 's move-constructor is defined this way: I can't say for sure; but an optional is not like a vector with max size of 1. It's more like a variable with a validity flag tacked on. Accordingly, it makes sense for moving an optional to be like moving the variable.



            If moving an optional left the old one "empty", then a = std::move(b); would invoke the destructor of b's managed object, which would be unexpected (to me, at least).






            share|improve this answer














            Unless otherwise specified, a moved-from object of class type is left in a valid but unspecified state. Not necessarily a "reset state", and definitely not "invalidated".



            For primitive types , moving is the same as copying, i.e. the source is unchanged.



            The defaulted move-constructor for a class type with primitive members will move each member, i.e. leave the primitive members unchanged; a user-defined move constructor might or might not "reset" them.



            A moved-from vector may or may not still have elements in it. We would expect it not to, since that's efficient, but it cannot be relied on.



            A moved-from std::string may still have elements in it, because of Small String Optimization.




            move on std::optional is actually specified by the standard (C++17 [optional.ctor]/7). It is defined as doing move on the contained type, if present. It does not turn a valued optional into a valueless optional.



            So it is actually expected that your code outputs true true, and the actual contained value in foo should stay the same too.




            Regarding the question of why std::optional 's move-constructor is defined this way: I can't say for sure; but an optional is not like a vector with max size of 1. It's more like a variable with a validity flag tacked on. Accordingly, it makes sense for moving an optional to be like moving the variable.



            If moving an optional left the old one "empty", then a = std::move(b); would invoke the destructor of b's managed object, which would be unexpected (to me, at least).







            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Aug 13 at 1:58

























            answered Aug 12 at 2:10









            M.M

            100k10104222




            100k10104222






















                up vote
                17
                down vote













                In a word: Performance.



                One of the chief motivating reasons for move semantics to exist in the first place is performance. So the special operations move construction and move assignment should be as fast as possible for all types.



                In order to assist this goal, it is standard practice that moved-from objects be left in a valid but unspecified state. So the very minimum that optional move construction/assignment need to do is to move from the source argument. To specify setting the source to not have a value after the move is equivalent to saying:




                After you move, do some extra, unnecessary work.




                No matter how small that extra work is, it is non-zero. Some (and I dare say many) clients will not need that extra work, and should not have to pay for it. Clients who do need it can easily add x.reset() after the move, putting the moved-from optional into a well-specified state.






                share|improve this answer






















                • Problem is that most(all?) std implementations do the wrong thing with std::string so they give unreasonable expectations to users. :/
                  – NoSenseEtAl
                  Aug 18 at 10:14











                • @NoSenseEtAl: I can only speak for the libc++ std::string. It does indeed leave a moved-from string empty, but not because it is "wrong", but because that is the fastest thing for this design. The libc++ string was actually designed from the move members outward. It copies all of the bits of the string object, and then zeros all of the bits of the source string object. It does not check whether the string is long or short. This copy&zero algorithm is correct whether the string is in the long or short mode. It would be incorrect to avoid the zero when in the long mode.
                  – Howard Hinnant
                  Aug 18 at 13:41










                • I find it weird that it is faster, since anyway destination string will need to branch on long or short because it needs to know if it is storing pointers or internal buffer, but I trust you. :)
                  – NoSenseEtAl
                  Aug 19 at 3:44







                • 1




                  Another nice thing about libc++ is that its source is so easily inspectable. ;-) github.com/llvm-mirror/libcxx/blob/master/include/…
                  – Howard Hinnant
                  Aug 19 at 13:42










                • well github has bad code navigation, but anyways you would need benchmarks, not just the source, but like I said I believe you, since I assume you did them when you implemented string rvr ctor. :)
                  – NoSenseEtAl
                  Aug 19 at 14:23














                up vote
                17
                down vote













                In a word: Performance.



                One of the chief motivating reasons for move semantics to exist in the first place is performance. So the special operations move construction and move assignment should be as fast as possible for all types.



                In order to assist this goal, it is standard practice that moved-from objects be left in a valid but unspecified state. So the very minimum that optional move construction/assignment need to do is to move from the source argument. To specify setting the source to not have a value after the move is equivalent to saying:




                After you move, do some extra, unnecessary work.




                No matter how small that extra work is, it is non-zero. Some (and I dare say many) clients will not need that extra work, and should not have to pay for it. Clients who do need it can easily add x.reset() after the move, putting the moved-from optional into a well-specified state.






                share|improve this answer






















                • Problem is that most(all?) std implementations do the wrong thing with std::string so they give unreasonable expectations to users. :/
                  – NoSenseEtAl
                  Aug 18 at 10:14











                • @NoSenseEtAl: I can only speak for the libc++ std::string. It does indeed leave a moved-from string empty, but not because it is "wrong", but because that is the fastest thing for this design. The libc++ string was actually designed from the move members outward. It copies all of the bits of the string object, and then zeros all of the bits of the source string object. It does not check whether the string is long or short. This copy&zero algorithm is correct whether the string is in the long or short mode. It would be incorrect to avoid the zero when in the long mode.
                  – Howard Hinnant
                  Aug 18 at 13:41










                • I find it weird that it is faster, since anyway destination string will need to branch on long or short because it needs to know if it is storing pointers or internal buffer, but I trust you. :)
                  – NoSenseEtAl
                  Aug 19 at 3:44







                • 1




                  Another nice thing about libc++ is that its source is so easily inspectable. ;-) github.com/llvm-mirror/libcxx/blob/master/include/…
                  – Howard Hinnant
                  Aug 19 at 13:42










                • well github has bad code navigation, but anyways you would need benchmarks, not just the source, but like I said I believe you, since I assume you did them when you implemented string rvr ctor. :)
                  – NoSenseEtAl
                  Aug 19 at 14:23












                up vote
                17
                down vote










                up vote
                17
                down vote









                In a word: Performance.



                One of the chief motivating reasons for move semantics to exist in the first place is performance. So the special operations move construction and move assignment should be as fast as possible for all types.



                In order to assist this goal, it is standard practice that moved-from objects be left in a valid but unspecified state. So the very minimum that optional move construction/assignment need to do is to move from the source argument. To specify setting the source to not have a value after the move is equivalent to saying:




                After you move, do some extra, unnecessary work.




                No matter how small that extra work is, it is non-zero. Some (and I dare say many) clients will not need that extra work, and should not have to pay for it. Clients who do need it can easily add x.reset() after the move, putting the moved-from optional into a well-specified state.






                share|improve this answer














                In a word: Performance.



                One of the chief motivating reasons for move semantics to exist in the first place is performance. So the special operations move construction and move assignment should be as fast as possible for all types.



                In order to assist this goal, it is standard practice that moved-from objects be left in a valid but unspecified state. So the very minimum that optional move construction/assignment need to do is to move from the source argument. To specify setting the source to not have a value after the move is equivalent to saying:




                After you move, do some extra, unnecessary work.




                No matter how small that extra work is, it is non-zero. Some (and I dare say many) clients will not need that extra work, and should not have to pay for it. Clients who do need it can easily add x.reset() after the move, putting the moved-from optional into a well-specified state.







                share|improve this answer














                share|improve this answer



                share|improve this answer








                edited Aug 13 at 1:22

























                answered Aug 12 at 13:40









                Howard Hinnant

                136k23297425




                136k23297425











                • Problem is that most(all?) std implementations do the wrong thing with std::string so they give unreasonable expectations to users. :/
                  – NoSenseEtAl
                  Aug 18 at 10:14











                • @NoSenseEtAl: I can only speak for the libc++ std::string. It does indeed leave a moved-from string empty, but not because it is "wrong", but because that is the fastest thing for this design. The libc++ string was actually designed from the move members outward. It copies all of the bits of the string object, and then zeros all of the bits of the source string object. It does not check whether the string is long or short. This copy&zero algorithm is correct whether the string is in the long or short mode. It would be incorrect to avoid the zero when in the long mode.
                  – Howard Hinnant
                  Aug 18 at 13:41










                • I find it weird that it is faster, since anyway destination string will need to branch on long or short because it needs to know if it is storing pointers or internal buffer, but I trust you. :)
                  – NoSenseEtAl
                  Aug 19 at 3:44







                • 1




                  Another nice thing about libc++ is that its source is so easily inspectable. ;-) github.com/llvm-mirror/libcxx/blob/master/include/…
                  – Howard Hinnant
                  Aug 19 at 13:42










                • well github has bad code navigation, but anyways you would need benchmarks, not just the source, but like I said I believe you, since I assume you did them when you implemented string rvr ctor. :)
                  – NoSenseEtAl
                  Aug 19 at 14:23
















                • Problem is that most(all?) std implementations do the wrong thing with std::string so they give unreasonable expectations to users. :/
                  – NoSenseEtAl
                  Aug 18 at 10:14











                • @NoSenseEtAl: I can only speak for the libc++ std::string. It does indeed leave a moved-from string empty, but not because it is "wrong", but because that is the fastest thing for this design. The libc++ string was actually designed from the move members outward. It copies all of the bits of the string object, and then zeros all of the bits of the source string object. It does not check whether the string is long or short. This copy&zero algorithm is correct whether the string is in the long or short mode. It would be incorrect to avoid the zero when in the long mode.
                  – Howard Hinnant
                  Aug 18 at 13:41










                • I find it weird that it is faster, since anyway destination string will need to branch on long or short because it needs to know if it is storing pointers or internal buffer, but I trust you. :)
                  – NoSenseEtAl
                  Aug 19 at 3:44







                • 1




                  Another nice thing about libc++ is that its source is so easily inspectable. ;-) github.com/llvm-mirror/libcxx/blob/master/include/…
                  – Howard Hinnant
                  Aug 19 at 13:42










                • well github has bad code navigation, but anyways you would need benchmarks, not just the source, but like I said I believe you, since I assume you did them when you implemented string rvr ctor. :)
                  – NoSenseEtAl
                  Aug 19 at 14:23















                Problem is that most(all?) std implementations do the wrong thing with std::string so they give unreasonable expectations to users. :/
                – NoSenseEtAl
                Aug 18 at 10:14





                Problem is that most(all?) std implementations do the wrong thing with std::string so they give unreasonable expectations to users. :/
                – NoSenseEtAl
                Aug 18 at 10:14













                @NoSenseEtAl: I can only speak for the libc++ std::string. It does indeed leave a moved-from string empty, but not because it is "wrong", but because that is the fastest thing for this design. The libc++ string was actually designed from the move members outward. It copies all of the bits of the string object, and then zeros all of the bits of the source string object. It does not check whether the string is long or short. This copy&zero algorithm is correct whether the string is in the long or short mode. It would be incorrect to avoid the zero when in the long mode.
                – Howard Hinnant
                Aug 18 at 13:41




                @NoSenseEtAl: I can only speak for the libc++ std::string. It does indeed leave a moved-from string empty, but not because it is "wrong", but because that is the fastest thing for this design. The libc++ string was actually designed from the move members outward. It copies all of the bits of the string object, and then zeros all of the bits of the source string object. It does not check whether the string is long or short. This copy&zero algorithm is correct whether the string is in the long or short mode. It would be incorrect to avoid the zero when in the long mode.
                – Howard Hinnant
                Aug 18 at 13:41












                I find it weird that it is faster, since anyway destination string will need to branch on long or short because it needs to know if it is storing pointers or internal buffer, but I trust you. :)
                – NoSenseEtAl
                Aug 19 at 3:44





                I find it weird that it is faster, since anyway destination string will need to branch on long or short because it needs to know if it is storing pointers or internal buffer, but I trust you. :)
                – NoSenseEtAl
                Aug 19 at 3:44





                1




                1




                Another nice thing about libc++ is that its source is so easily inspectable. ;-) github.com/llvm-mirror/libcxx/blob/master/include/…
                – Howard Hinnant
                Aug 19 at 13:42




                Another nice thing about libc++ is that its source is so easily inspectable. ;-) github.com/llvm-mirror/libcxx/blob/master/include/…
                – Howard Hinnant
                Aug 19 at 13:42












                well github has bad code navigation, but anyways you would need benchmarks, not just the source, but like I said I believe you, since I assume you did them when you implemented string rvr ctor. :)
                – NoSenseEtAl
                Aug 19 at 14:23




                well github has bad code navigation, but anyways you would need benchmarks, not just the source, but like I said I believe you, since I assume you did them when you implemented string rvr ctor. :)
                – NoSenseEtAl
                Aug 19 at 14:23










                up vote
                4
                down vote













                What that paragraph says is that if that optional had a value, it still has a value. Since that value has been moved from (to the newly constructed object), it could be a different value than what it had before the move. This allows you to access the moved-from optional object the same way as a moved-from non-optional object, so the behavior of a T vs. optional<T> (when it contains an object) when accessed after the move is the same.



                Also, the overall effect of a move from an optional depends on how the contained type T handles a move. Other classes (like vector) do not have this dependency.






                share|improve this answer
























                  up vote
                  4
                  down vote













                  What that paragraph says is that if that optional had a value, it still has a value. Since that value has been moved from (to the newly constructed object), it could be a different value than what it had before the move. This allows you to access the moved-from optional object the same way as a moved-from non-optional object, so the behavior of a T vs. optional<T> (when it contains an object) when accessed after the move is the same.



                  Also, the overall effect of a move from an optional depends on how the contained type T handles a move. Other classes (like vector) do not have this dependency.






                  share|improve this answer






















                    up vote
                    4
                    down vote










                    up vote
                    4
                    down vote









                    What that paragraph says is that if that optional had a value, it still has a value. Since that value has been moved from (to the newly constructed object), it could be a different value than what it had before the move. This allows you to access the moved-from optional object the same way as a moved-from non-optional object, so the behavior of a T vs. optional<T> (when it contains an object) when accessed after the move is the same.



                    Also, the overall effect of a move from an optional depends on how the contained type T handles a move. Other classes (like vector) do not have this dependency.






                    share|improve this answer












                    What that paragraph says is that if that optional had a value, it still has a value. Since that value has been moved from (to the newly constructed object), it could be a different value than what it had before the move. This allows you to access the moved-from optional object the same way as a moved-from non-optional object, so the behavior of a T vs. optional<T> (when it contains an object) when accessed after the move is the same.



                    Also, the overall effect of a move from an optional depends on how the contained type T handles a move. Other classes (like vector) do not have this dependency.







                    share|improve this answer












                    share|improve this answer



                    share|improve this answer










                    answered Aug 12 at 1:57









                    1201ProgramAlarm

                    15k32338




                    15k32338




















                        up vote
                        2
                        down vote













                        While it might be reasonable to expect that std::optonal behaves similar to std::unique_ptr which resets state of moved-from object, there are reasons not to demand such behavior. I think one of them is that std::optional of a trivial type should be a trivially copyable type. As such it cannot have non-defaulted move constructor and cannot reset has_value flag.



                        Having std::optional for a non-trivial type behave differently from optional for a trivial type is a rather bad idea.






                        share|improve this answer
























                          up vote
                          2
                          down vote













                          While it might be reasonable to expect that std::optonal behaves similar to std::unique_ptr which resets state of moved-from object, there are reasons not to demand such behavior. I think one of them is that std::optional of a trivial type should be a trivially copyable type. As such it cannot have non-defaulted move constructor and cannot reset has_value flag.



                          Having std::optional for a non-trivial type behave differently from optional for a trivial type is a rather bad idea.






                          share|improve this answer






















                            up vote
                            2
                            down vote










                            up vote
                            2
                            down vote









                            While it might be reasonable to expect that std::optonal behaves similar to std::unique_ptr which resets state of moved-from object, there are reasons not to demand such behavior. I think one of them is that std::optional of a trivial type should be a trivially copyable type. As such it cannot have non-defaulted move constructor and cannot reset has_value flag.



                            Having std::optional for a non-trivial type behave differently from optional for a trivial type is a rather bad idea.






                            share|improve this answer












                            While it might be reasonable to expect that std::optonal behaves similar to std::unique_ptr which resets state of moved-from object, there are reasons not to demand such behavior. I think one of them is that std::optional of a trivial type should be a trivially copyable type. As such it cannot have non-defaulted move constructor and cannot reset has_value flag.



                            Having std::optional for a non-trivial type behave differently from optional for a trivial type is a rather bad idea.







                            share|improve this answer












                            share|improve this answer



                            share|improve this answer










                            answered Aug 12 at 13:45









                            Григорий Шуренков

                            32728




                            32728



























                                 

                                draft saved


                                draft discarded















































                                 


                                draft saved


                                draft discarded














                                StackExchange.ready(
                                function ()
                                StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f51805059%2fwhy-does-moving-stdoptional-not-reset-state%23new-answer', 'question_page');

                                );

                                Post as a guest













































































                                Comments

                                Popular posts from this blog

                                What does second last employer means? [closed]

                                List of Gilmore Girls characters

                                Confectionery