Since C++11 I have been using the ternary operator to move or throw based on some condition, but with latest GCC (9.1 and trunk) is not working anymore.
I have reduced the problem to this example (Wandbox permalink):
#include <iostream>
#include <memory>
int main()
{
auto p = std::make_unique<int>();
std::cout << "p.get(): " << p.get() << std::endl;
{
std::cout << "Move p into q" << std::endl;
auto q = p ? std::move(p) : throw std::invalid_argument{"null ptr"};
std::cout << "q.get(): " << q.get() << std::endl;
}
std::cout << "p.get(): " << p.get() << std::endl;
return 0;
}
It works with GCC 8.3 and older, and with every Clang version; and p
is moved:
p.get(): 0xde5c20
Move p into q
q.get(): 0xde5c20
p.get(): 0
But now with GCC 9.1 and later it doesn't work:
p.get(): 0x1d89150
Move p into q
q.get(): 0x1d89150
p.get(): 0x1d89150
And then the program crashes due to a double free.
Is this a bug in GCC 9.1/trunk? Or latest GCC is the only one doing the right thing and this is not valid C++?
The conditional (ternary) operator is the only JavaScript operator that takes three operands: a condition followed by a question mark ( ? ), then an expression to execute if the condition is truthy followed by a colon ( : ), and finally the expression to execute if the condition is falsy.
Example: C Ternary Operator Here, age >= 18 - test condition that checks if input value is greater or equal to 18. printf("You can vote") - expression1 that is executed if condition is true. printf("You cannot vote") - expression2 that is executed if condition is false.
In C++, the ternary operator can be used to replace certain types of if...else statements. Negative Number! Here, both programs give the same output. However, the use of the ternary operator makes our code more readable and clean.
Moreover, as has been pointed out, at the byte code level there's really no difference between the ternary operator and if-then-else. As in the above example, the decision on which to choose is based wholly on readability.
This has to be a bug.
Either the move will be a move or the compilation should fail due to attempted copy of a unique_ptr
(or a throw
occurs in which case it doesn't matter).
q.get() == p.get()
indeed shows that the internals have broken down, as this should not be possible.
I'd agree with cpplearner that this is bug 90393 (and all its dupes), which is reported as having been introduced in GCC 9.1.
Either downgrade, wait to upgrade, or reform your code into a nice if
/else
. 😊
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With