How is std::optional never “valueless by exception”?How do you set, clear, and toggle a single bit?How to concatenate a std::string and an int?What's the best way to trim std::string?How do I iterate over the words of a string?How to convert std::string to lower case?How to convert a std::string to const char* or char*?How can I profile C++ code running on Linux?std::wstring VS std::stringWhy is “using namespace std;” considered bad practice?Am I abusing std::optional
Why does a sticker slowly peel off, but if it is pulled quickly it tears?
What ways are there to "PEEK" memory sections in (different) BASIC(s)
How do I portray irrational anger in first person?
Do multi-engine jets need all engines with equal age to reduce asymmetry in thrust and fuel consumption arising out of deterioration?
To what extent should we fear giving offense?
How to handle inventory and story of a player leaving
Was the six engine Boeing-747 ever thought about?
Why does the weaker C–H bond have a higher wavenumber than the C=O bond?
Should I ask for a raise one month before the end of an internship?
How to prevent a hosting company from accessing a VM's encryption keys?
Did the Apollo Guidance Computer really use 60% of the world's ICs in 1963?
Why is there not a willingness from the world to step in between Pakistan and India?
Why did the population of Bhutan drop by 70% between 2007 and 2008?
How does attacking during a conversation affect initiative?
Can I lend a small amount of my own money to a bank at the federal funds rate?
What to do about my 1-month-old boy peeing through diapers?
Why did Lucius make a deal out of Buckbeak hurting Draco but not about Draco being turned into a ferret?
Why does this London Underground poster from 1924 have a Star of David atop a Christmas tree?
Is it unusual for a math department not to have a mail/web server?
Heat output from a 200W electric radiator?
Why can't you say don't instead of won't?
Looking for a plural noun related to ‘fulcrum’ or ‘pivot’ that denotes multiple things as crucial to success
Group riding etiquette
Alternatives to Network Backup
How is std::optional never “valueless by exception”?
How do you set, clear, and toggle a single bit?How to concatenate a std::string and an int?What's the best way to trim std::string?How do I iterate over the words of a string?How to convert std::string to lower case?How to convert a std::string to const char* or char*?How can I profile C++ code running on Linux?std::wstring VS std::stringWhy is “using namespace std;” considered bad practice?Am I abusing std::optional
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;
std::variant
can enter a state called "valueless by exception".
As I understand, the common cause of this is if a move assignment throws an exception. The variant's old value isn't guaranteed to be present anymore, and neither is the intended new value.
std::optional
, however, doesn't have such a state. cppreference makes the bold claim:
If an exception is thrown, the initialization state of *this ... is unchanged, i.e. if the object contained a value, it still contains a value, and the other way round.
How is std::optional
able to avoid becoming "valueless by exception", while std::variant
is not?
c++ c++17 stdoptional std-variant
add a comment |
std::variant
can enter a state called "valueless by exception".
As I understand, the common cause of this is if a move assignment throws an exception. The variant's old value isn't guaranteed to be present anymore, and neither is the intended new value.
std::optional
, however, doesn't have such a state. cppreference makes the bold claim:
If an exception is thrown, the initialization state of *this ... is unchanged, i.e. if the object contained a value, it still contains a value, and the other way round.
How is std::optional
able to avoid becoming "valueless by exception", while std::variant
is not?
c++ c++17 stdoptional std-variant
add a comment |
std::variant
can enter a state called "valueless by exception".
As I understand, the common cause of this is if a move assignment throws an exception. The variant's old value isn't guaranteed to be present anymore, and neither is the intended new value.
std::optional
, however, doesn't have such a state. cppreference makes the bold claim:
If an exception is thrown, the initialization state of *this ... is unchanged, i.e. if the object contained a value, it still contains a value, and the other way round.
How is std::optional
able to avoid becoming "valueless by exception", while std::variant
is not?
c++ c++17 stdoptional std-variant
std::variant
can enter a state called "valueless by exception".
As I understand, the common cause of this is if a move assignment throws an exception. The variant's old value isn't guaranteed to be present anymore, and neither is the intended new value.
std::optional
, however, doesn't have such a state. cppreference makes the bold claim:
If an exception is thrown, the initialization state of *this ... is unchanged, i.e. if the object contained a value, it still contains a value, and the other way round.
How is std::optional
able to avoid becoming "valueless by exception", while std::variant
is not?
c++ c++17 stdoptional std-variant
c++ c++17 stdoptional std-variant
asked 8 hours ago
Drew DormannDrew Dormann
42.8k9 gold badges87 silver badges144 bronze badges
42.8k9 gold badges87 silver badges144 bronze badges
add a comment |
add a comment |
3 Answers
3
active
oldest
votes
optional<T>
has one of two states:
- a
T
- empty
A variant
can only enter the valueless state when transitioning from one state to another if transitioning will throw - because you need to somehow recover the original object and the various strategies for doing so require either extra storage1, heap allocation2, or an empty state3.
But for optional
, transitioning from T
to empty is just a destruction. So that only throws if T
's destructor throws, and really who cares at that point. And transitioning from empty to T
is not an issue - if that throws, it's easy to recover the original object: the empty state is empty.
The challenging case is: emplace()
when we already had a T
. We necessarily need to have destroyed the original object, so what do we do if the emplace construction throws? With optional
, we have a known, convenient empty state to fallback to - so the design is just to do that.
variant
's problems from not having that easy state to recover to.
1 As boost::variant2
does.
2 As boost::variant
does.
3 I'm not sure of a variant implementation that does this, but there was a design suggestion that variant<monostate, A, B>
could transition into the monostate
state if it held an A
and the transition to B
threw.
"and really who cares at that point" aka nasal demons.
– T.C.
8 hours ago
I don't see how this answer addresses the case of anoptional<T>
going fromT
to a differentT
state. Note thatemplace
andoperator=
have different behavior here in the case of an exception being thrown in the process!
– Max Langhof
8 hours ago
@MaxLanghof: If the constructor throws inemplace
, then theoptional
is explicitly stated to be unengaged. Ifoperator=
throws during construction, then there's similarly no value. Barry's point remains valid: it works because there is always a legitimate empty state that theoptional
can go to.variant
doesn't have that luxury becausevariant
cannot be empty.
– Nicol Bolas
7 hours ago
@NicolBolas The difficult case (and the one most similar to thevariant
problem) is assigning a new value when you have an existing one. And the core of retaining the initialization state is usingT::operator=
- this specific case involves no emptyoptional
and no destructor at all. Since all the cases covered in this answer regardingstd::optional
involve either destruction or empty states, I think this important case (covered by the other answers) is missing. Don't get me wrong, this answer covers all the other aspects just fine, but I had to read up on this last case myself...
– Max Langhof
7 hours ago
add a comment |
std::optional
has it easy:
It contains a value and a new value is assigned:
Easy, just delegate to the assignment operator and let it deal with it. Even in the case of an exception, there will still be a value left.It contains a value and the value is removed:
Easy, the dtor must not throw. The standard library generally assumes that for user-defined types.It contains no value and one is assigned:
Reverting to no value in the face of an exception on constructing is simple enough.It contains no value and no value is assigned:
Trivial.
std::variant
has the same easy time when the type stored does not change.
Unfortunately, when a different type is assigned it must make place for it by destroying the previous value, and then constructing the new value might throw!
As the previous value is already lost, what can you do?
Mark it as valueless by exception to have a stable, valid though undesirable state, and let the exception propagate.
One could use extra space and time to allocate the values dynamically, save the old value somewhere temporarily, construct the new value before assigning or the like, but all those strategies are costly, and only the first always works.
add a comment |
"valueless by exception" refers to a specific scenario where you need to change the type stored in the variant. That necessarily requires 1) destroying the old value and then 2) creating the new one in its place. If 2) fails, you have no way to go back (without undue overhead unacceptable to the committee).
optional
doesn't have this problem. If some operation on the object it contains throws an exception, so be it. The object is still there. That doesn't mean that the object's state is still meaningful - it's whatever the throwing operation leaves it in. Hopefully that operation has at least the basic guarantee.
"the initialization state of *this is unchanged" ... am I misunderstanding that statement? I think you're saying that it could change to something not meaningful.
– Drew Dormann
8 hours ago
1
Fromoptional
's perspective, it's still holding an object. Whether that object is in a usable state is notoptional
's concern.
– T.C.
8 hours ago
It is quite an important detail thatstd::optional::operator=
usesT::operator=
instead of destroying + constructing theT
value.emplace
does the latter (and leaves theoptional
empty if construction of the new value throws).
– Max Langhof
8 hours ago
add a comment |
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
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f57696187%2fhow-is-stdoptional-never-valueless-by-exception%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
optional<T>
has one of two states:
- a
T
- empty
A variant
can only enter the valueless state when transitioning from one state to another if transitioning will throw - because you need to somehow recover the original object and the various strategies for doing so require either extra storage1, heap allocation2, or an empty state3.
But for optional
, transitioning from T
to empty is just a destruction. So that only throws if T
's destructor throws, and really who cares at that point. And transitioning from empty to T
is not an issue - if that throws, it's easy to recover the original object: the empty state is empty.
The challenging case is: emplace()
when we already had a T
. We necessarily need to have destroyed the original object, so what do we do if the emplace construction throws? With optional
, we have a known, convenient empty state to fallback to - so the design is just to do that.
variant
's problems from not having that easy state to recover to.
1 As boost::variant2
does.
2 As boost::variant
does.
3 I'm not sure of a variant implementation that does this, but there was a design suggestion that variant<monostate, A, B>
could transition into the monostate
state if it held an A
and the transition to B
threw.
"and really who cares at that point" aka nasal demons.
– T.C.
8 hours ago
I don't see how this answer addresses the case of anoptional<T>
going fromT
to a differentT
state. Note thatemplace
andoperator=
have different behavior here in the case of an exception being thrown in the process!
– Max Langhof
8 hours ago
@MaxLanghof: If the constructor throws inemplace
, then theoptional
is explicitly stated to be unengaged. Ifoperator=
throws during construction, then there's similarly no value. Barry's point remains valid: it works because there is always a legitimate empty state that theoptional
can go to.variant
doesn't have that luxury becausevariant
cannot be empty.
– Nicol Bolas
7 hours ago
@NicolBolas The difficult case (and the one most similar to thevariant
problem) is assigning a new value when you have an existing one. And the core of retaining the initialization state is usingT::operator=
- this specific case involves no emptyoptional
and no destructor at all. Since all the cases covered in this answer regardingstd::optional
involve either destruction or empty states, I think this important case (covered by the other answers) is missing. Don't get me wrong, this answer covers all the other aspects just fine, but I had to read up on this last case myself...
– Max Langhof
7 hours ago
add a comment |
optional<T>
has one of two states:
- a
T
- empty
A variant
can only enter the valueless state when transitioning from one state to another if transitioning will throw - because you need to somehow recover the original object and the various strategies for doing so require either extra storage1, heap allocation2, or an empty state3.
But for optional
, transitioning from T
to empty is just a destruction. So that only throws if T
's destructor throws, and really who cares at that point. And transitioning from empty to T
is not an issue - if that throws, it's easy to recover the original object: the empty state is empty.
The challenging case is: emplace()
when we already had a T
. We necessarily need to have destroyed the original object, so what do we do if the emplace construction throws? With optional
, we have a known, convenient empty state to fallback to - so the design is just to do that.
variant
's problems from not having that easy state to recover to.
1 As boost::variant2
does.
2 As boost::variant
does.
3 I'm not sure of a variant implementation that does this, but there was a design suggestion that variant<monostate, A, B>
could transition into the monostate
state if it held an A
and the transition to B
threw.
"and really who cares at that point" aka nasal demons.
– T.C.
8 hours ago
I don't see how this answer addresses the case of anoptional<T>
going fromT
to a differentT
state. Note thatemplace
andoperator=
have different behavior here in the case of an exception being thrown in the process!
– Max Langhof
8 hours ago
@MaxLanghof: If the constructor throws inemplace
, then theoptional
is explicitly stated to be unengaged. Ifoperator=
throws during construction, then there's similarly no value. Barry's point remains valid: it works because there is always a legitimate empty state that theoptional
can go to.variant
doesn't have that luxury becausevariant
cannot be empty.
– Nicol Bolas
7 hours ago
@NicolBolas The difficult case (and the one most similar to thevariant
problem) is assigning a new value when you have an existing one. And the core of retaining the initialization state is usingT::operator=
- this specific case involves no emptyoptional
and no destructor at all. Since all the cases covered in this answer regardingstd::optional
involve either destruction or empty states, I think this important case (covered by the other answers) is missing. Don't get me wrong, this answer covers all the other aspects just fine, but I had to read up on this last case myself...
– Max Langhof
7 hours ago
add a comment |
optional<T>
has one of two states:
- a
T
- empty
A variant
can only enter the valueless state when transitioning from one state to another if transitioning will throw - because you need to somehow recover the original object and the various strategies for doing so require either extra storage1, heap allocation2, or an empty state3.
But for optional
, transitioning from T
to empty is just a destruction. So that only throws if T
's destructor throws, and really who cares at that point. And transitioning from empty to T
is not an issue - if that throws, it's easy to recover the original object: the empty state is empty.
The challenging case is: emplace()
when we already had a T
. We necessarily need to have destroyed the original object, so what do we do if the emplace construction throws? With optional
, we have a known, convenient empty state to fallback to - so the design is just to do that.
variant
's problems from not having that easy state to recover to.
1 As boost::variant2
does.
2 As boost::variant
does.
3 I'm not sure of a variant implementation that does this, but there was a design suggestion that variant<monostate, A, B>
could transition into the monostate
state if it held an A
and the transition to B
threw.
optional<T>
has one of two states:
- a
T
- empty
A variant
can only enter the valueless state when transitioning from one state to another if transitioning will throw - because you need to somehow recover the original object and the various strategies for doing so require either extra storage1, heap allocation2, or an empty state3.
But for optional
, transitioning from T
to empty is just a destruction. So that only throws if T
's destructor throws, and really who cares at that point. And transitioning from empty to T
is not an issue - if that throws, it's easy to recover the original object: the empty state is empty.
The challenging case is: emplace()
when we already had a T
. We necessarily need to have destroyed the original object, so what do we do if the emplace construction throws? With optional
, we have a known, convenient empty state to fallback to - so the design is just to do that.
variant
's problems from not having that easy state to recover to.
1 As boost::variant2
does.
2 As boost::variant
does.
3 I'm not sure of a variant implementation that does this, but there was a design suggestion that variant<monostate, A, B>
could transition into the monostate
state if it held an A
and the transition to B
threw.
edited 7 hours ago
answered 8 hours ago
BarryBarry
198k22 gold badges368 silver badges659 bronze badges
198k22 gold badges368 silver badges659 bronze badges
"and really who cares at that point" aka nasal demons.
– T.C.
8 hours ago
I don't see how this answer addresses the case of anoptional<T>
going fromT
to a differentT
state. Note thatemplace
andoperator=
have different behavior here in the case of an exception being thrown in the process!
– Max Langhof
8 hours ago
@MaxLanghof: If the constructor throws inemplace
, then theoptional
is explicitly stated to be unengaged. Ifoperator=
throws during construction, then there's similarly no value. Barry's point remains valid: it works because there is always a legitimate empty state that theoptional
can go to.variant
doesn't have that luxury becausevariant
cannot be empty.
– Nicol Bolas
7 hours ago
@NicolBolas The difficult case (and the one most similar to thevariant
problem) is assigning a new value when you have an existing one. And the core of retaining the initialization state is usingT::operator=
- this specific case involves no emptyoptional
and no destructor at all. Since all the cases covered in this answer regardingstd::optional
involve either destruction or empty states, I think this important case (covered by the other answers) is missing. Don't get me wrong, this answer covers all the other aspects just fine, but I had to read up on this last case myself...
– Max Langhof
7 hours ago
add a comment |
"and really who cares at that point" aka nasal demons.
– T.C.
8 hours ago
I don't see how this answer addresses the case of anoptional<T>
going fromT
to a differentT
state. Note thatemplace
andoperator=
have different behavior here in the case of an exception being thrown in the process!
– Max Langhof
8 hours ago
@MaxLanghof: If the constructor throws inemplace
, then theoptional
is explicitly stated to be unengaged. Ifoperator=
throws during construction, then there's similarly no value. Barry's point remains valid: it works because there is always a legitimate empty state that theoptional
can go to.variant
doesn't have that luxury becausevariant
cannot be empty.
– Nicol Bolas
7 hours ago
@NicolBolas The difficult case (and the one most similar to thevariant
problem) is assigning a new value when you have an existing one. And the core of retaining the initialization state is usingT::operator=
- this specific case involves no emptyoptional
and no destructor at all. Since all the cases covered in this answer regardingstd::optional
involve either destruction or empty states, I think this important case (covered by the other answers) is missing. Don't get me wrong, this answer covers all the other aspects just fine, but I had to read up on this last case myself...
– Max Langhof
7 hours ago
"and really who cares at that point" aka nasal demons.
– T.C.
8 hours ago
"and really who cares at that point" aka nasal demons.
– T.C.
8 hours ago
I don't see how this answer addresses the case of an
optional<T>
going from T
to a different T
state. Note that emplace
and operator=
have different behavior here in the case of an exception being thrown in the process!– Max Langhof
8 hours ago
I don't see how this answer addresses the case of an
optional<T>
going from T
to a different T
state. Note that emplace
and operator=
have different behavior here in the case of an exception being thrown in the process!– Max Langhof
8 hours ago
@MaxLanghof: If the constructor throws in
emplace
, then the optional
is explicitly stated to be unengaged. If operator=
throws during construction, then there's similarly no value. Barry's point remains valid: it works because there is always a legitimate empty state that the optional
can go to. variant
doesn't have that luxury because variant
cannot be empty.– Nicol Bolas
7 hours ago
@MaxLanghof: If the constructor throws in
emplace
, then the optional
is explicitly stated to be unengaged. If operator=
throws during construction, then there's similarly no value. Barry's point remains valid: it works because there is always a legitimate empty state that the optional
can go to. variant
doesn't have that luxury because variant
cannot be empty.– Nicol Bolas
7 hours ago
@NicolBolas The difficult case (and the one most similar to the
variant
problem) is assigning a new value when you have an existing one. And the core of retaining the initialization state is using T::operator=
- this specific case involves no empty optional
and no destructor at all. Since all the cases covered in this answer regarding std::optional
involve either destruction or empty states, I think this important case (covered by the other answers) is missing. Don't get me wrong, this answer covers all the other aspects just fine, but I had to read up on this last case myself...– Max Langhof
7 hours ago
@NicolBolas The difficult case (and the one most similar to the
variant
problem) is assigning a new value when you have an existing one. And the core of retaining the initialization state is using T::operator=
- this specific case involves no empty optional
and no destructor at all. Since all the cases covered in this answer regarding std::optional
involve either destruction or empty states, I think this important case (covered by the other answers) is missing. Don't get me wrong, this answer covers all the other aspects just fine, but I had to read up on this last case myself...– Max Langhof
7 hours ago
add a comment |
std::optional
has it easy:
It contains a value and a new value is assigned:
Easy, just delegate to the assignment operator and let it deal with it. Even in the case of an exception, there will still be a value left.It contains a value and the value is removed:
Easy, the dtor must not throw. The standard library generally assumes that for user-defined types.It contains no value and one is assigned:
Reverting to no value in the face of an exception on constructing is simple enough.It contains no value and no value is assigned:
Trivial.
std::variant
has the same easy time when the type stored does not change.
Unfortunately, when a different type is assigned it must make place for it by destroying the previous value, and then constructing the new value might throw!
As the previous value is already lost, what can you do?
Mark it as valueless by exception to have a stable, valid though undesirable state, and let the exception propagate.
One could use extra space and time to allocate the values dynamically, save the old value somewhere temporarily, construct the new value before assigning or the like, but all those strategies are costly, and only the first always works.
add a comment |
std::optional
has it easy:
It contains a value and a new value is assigned:
Easy, just delegate to the assignment operator and let it deal with it. Even in the case of an exception, there will still be a value left.It contains a value and the value is removed:
Easy, the dtor must not throw. The standard library generally assumes that for user-defined types.It contains no value and one is assigned:
Reverting to no value in the face of an exception on constructing is simple enough.It contains no value and no value is assigned:
Trivial.
std::variant
has the same easy time when the type stored does not change.
Unfortunately, when a different type is assigned it must make place for it by destroying the previous value, and then constructing the new value might throw!
As the previous value is already lost, what can you do?
Mark it as valueless by exception to have a stable, valid though undesirable state, and let the exception propagate.
One could use extra space and time to allocate the values dynamically, save the old value somewhere temporarily, construct the new value before assigning or the like, but all those strategies are costly, and only the first always works.
add a comment |
std::optional
has it easy:
It contains a value and a new value is assigned:
Easy, just delegate to the assignment operator and let it deal with it. Even in the case of an exception, there will still be a value left.It contains a value and the value is removed:
Easy, the dtor must not throw. The standard library generally assumes that for user-defined types.It contains no value and one is assigned:
Reverting to no value in the face of an exception on constructing is simple enough.It contains no value and no value is assigned:
Trivial.
std::variant
has the same easy time when the type stored does not change.
Unfortunately, when a different type is assigned it must make place for it by destroying the previous value, and then constructing the new value might throw!
As the previous value is already lost, what can you do?
Mark it as valueless by exception to have a stable, valid though undesirable state, and let the exception propagate.
One could use extra space and time to allocate the values dynamically, save the old value somewhere temporarily, construct the new value before assigning or the like, but all those strategies are costly, and only the first always works.
std::optional
has it easy:
It contains a value and a new value is assigned:
Easy, just delegate to the assignment operator and let it deal with it. Even in the case of an exception, there will still be a value left.It contains a value and the value is removed:
Easy, the dtor must not throw. The standard library generally assumes that for user-defined types.It contains no value and one is assigned:
Reverting to no value in the face of an exception on constructing is simple enough.It contains no value and no value is assigned:
Trivial.
std::variant
has the same easy time when the type stored does not change.
Unfortunately, when a different type is assigned it must make place for it by destroying the previous value, and then constructing the new value might throw!
As the previous value is already lost, what can you do?
Mark it as valueless by exception to have a stable, valid though undesirable state, and let the exception propagate.
One could use extra space and time to allocate the values dynamically, save the old value somewhere temporarily, construct the new value before assigning or the like, but all those strategies are costly, and only the first always works.
edited 7 hours ago
answered 8 hours ago
DeduplicatorDeduplicator
37.4k6 gold badges52 silver badges91 bronze badges
37.4k6 gold badges52 silver badges91 bronze badges
add a comment |
add a comment |
"valueless by exception" refers to a specific scenario where you need to change the type stored in the variant. That necessarily requires 1) destroying the old value and then 2) creating the new one in its place. If 2) fails, you have no way to go back (without undue overhead unacceptable to the committee).
optional
doesn't have this problem. If some operation on the object it contains throws an exception, so be it. The object is still there. That doesn't mean that the object's state is still meaningful - it's whatever the throwing operation leaves it in. Hopefully that operation has at least the basic guarantee.
"the initialization state of *this is unchanged" ... am I misunderstanding that statement? I think you're saying that it could change to something not meaningful.
– Drew Dormann
8 hours ago
1
Fromoptional
's perspective, it's still holding an object. Whether that object is in a usable state is notoptional
's concern.
– T.C.
8 hours ago
It is quite an important detail thatstd::optional::operator=
usesT::operator=
instead of destroying + constructing theT
value.emplace
does the latter (and leaves theoptional
empty if construction of the new value throws).
– Max Langhof
8 hours ago
add a comment |
"valueless by exception" refers to a specific scenario where you need to change the type stored in the variant. That necessarily requires 1) destroying the old value and then 2) creating the new one in its place. If 2) fails, you have no way to go back (without undue overhead unacceptable to the committee).
optional
doesn't have this problem. If some operation on the object it contains throws an exception, so be it. The object is still there. That doesn't mean that the object's state is still meaningful - it's whatever the throwing operation leaves it in. Hopefully that operation has at least the basic guarantee.
"the initialization state of *this is unchanged" ... am I misunderstanding that statement? I think you're saying that it could change to something not meaningful.
– Drew Dormann
8 hours ago
1
Fromoptional
's perspective, it's still holding an object. Whether that object is in a usable state is notoptional
's concern.
– T.C.
8 hours ago
It is quite an important detail thatstd::optional::operator=
usesT::operator=
instead of destroying + constructing theT
value.emplace
does the latter (and leaves theoptional
empty if construction of the new value throws).
– Max Langhof
8 hours ago
add a comment |
"valueless by exception" refers to a specific scenario where you need to change the type stored in the variant. That necessarily requires 1) destroying the old value and then 2) creating the new one in its place. If 2) fails, you have no way to go back (without undue overhead unacceptable to the committee).
optional
doesn't have this problem. If some operation on the object it contains throws an exception, so be it. The object is still there. That doesn't mean that the object's state is still meaningful - it's whatever the throwing operation leaves it in. Hopefully that operation has at least the basic guarantee.
"valueless by exception" refers to a specific scenario where you need to change the type stored in the variant. That necessarily requires 1) destroying the old value and then 2) creating the new one in its place. If 2) fails, you have no way to go back (without undue overhead unacceptable to the committee).
optional
doesn't have this problem. If some operation on the object it contains throws an exception, so be it. The object is still there. That doesn't mean that the object's state is still meaningful - it's whatever the throwing operation leaves it in. Hopefully that operation has at least the basic guarantee.
edited 8 hours ago
answered 8 hours ago
T.C.T.C.
111k14 gold badges228 silver badges337 bronze badges
111k14 gold badges228 silver badges337 bronze badges
"the initialization state of *this is unchanged" ... am I misunderstanding that statement? I think you're saying that it could change to something not meaningful.
– Drew Dormann
8 hours ago
1
Fromoptional
's perspective, it's still holding an object. Whether that object is in a usable state is notoptional
's concern.
– T.C.
8 hours ago
It is quite an important detail thatstd::optional::operator=
usesT::operator=
instead of destroying + constructing theT
value.emplace
does the latter (and leaves theoptional
empty if construction of the new value throws).
– Max Langhof
8 hours ago
add a comment |
"the initialization state of *this is unchanged" ... am I misunderstanding that statement? I think you're saying that it could change to something not meaningful.
– Drew Dormann
8 hours ago
1
Fromoptional
's perspective, it's still holding an object. Whether that object is in a usable state is notoptional
's concern.
– T.C.
8 hours ago
It is quite an important detail thatstd::optional::operator=
usesT::operator=
instead of destroying + constructing theT
value.emplace
does the latter (and leaves theoptional
empty if construction of the new value throws).
– Max Langhof
8 hours ago
"the initialization state of *this is unchanged" ... am I misunderstanding that statement? I think you're saying that it could change to something not meaningful.
– Drew Dormann
8 hours ago
"the initialization state of *this is unchanged" ... am I misunderstanding that statement? I think you're saying that it could change to something not meaningful.
– Drew Dormann
8 hours ago
1
1
From
optional
's perspective, it's still holding an object. Whether that object is in a usable state is not optional
's concern.– T.C.
8 hours ago
From
optional
's perspective, it's still holding an object. Whether that object is in a usable state is not optional
's concern.– T.C.
8 hours ago
It is quite an important detail that
std::optional::operator=
uses T::operator=
instead of destroying + constructing the T
value. emplace
does the latter (and leaves the optional
empty if construction of the new value throws).– Max Langhof
8 hours ago
It is quite an important detail that
std::optional::operator=
uses T::operator=
instead of destroying + constructing the T
value. emplace
does the latter (and leaves the optional
empty if construction of the new value throws).– Max Langhof
8 hours ago
add a comment |
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.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f57696187%2fhow-is-stdoptional-never-valueless-by-exception%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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