Is there any difference between the evaluation of expressions between the two return statements below, based on the extra parenthesis?
return a++ *(-b+123.456)/999.12344;
vs
return (a++ *(-b+123.456)/999.12344);
Programming Language C++
Standards CPP 98'ish (Before C++11)
Hope the question is clear. Expectation is to evaluate the expression in full.
Sloppy speaking x is the same as (x) (see this answer for the "striclty speaking" answer ;). Adding parentheses around the full expression does not change anything about operator precedence.
PS: It has an obscure impact on return value optimization (see this answer for the details). Though, it definitely has no impact on the value that is returned.
There are differences. Using parentheses will obviate return value optimisation.
If, for example, a and / or b were objects with all suitable operators overloaded, then using parentheses could suffer you the overhead of an object value copy.
For plain-old-data there is no difference, subject to the C++11 abomination
decltype(auto) ub_server() { int a; return (a);}
which actually gives you a dangling reference.
In summary: Don't use the enclosing parentheses unless you want some of the above behaviour, and possibly only then with a supporting comment.
Is there any difference between the evaluation of expressions between the two return statements below, based on the extra parenthesis?
No; the parentheses are completely redundant in this case.
An expression expr is actually not the same as an expression (expr), and you can observe this with return because copy/move elision is inhibited in the latter case:
#include <iostream>
struct T
{
T() { std::cout << "T()\n"; }
T(const T&) { std::cout << "T(const T&)\n"; }
T(T&&) { std::cout << "T(T&&)\n"; }
~T() { std::cout << "~T()\n"; }
};
T foo()
{
T t;
return t;
}
T bar()
{
T t;
return (t);
}
int main()
{
std::cout << "Test 1\n------\n";
foo();
std::cout << '\n';
std::cout << "Test 2\n------\n";
bar();
}
Output:
Test 1
------
T()
~T()
Test 2
------
T()
T(T&&)
~T()
~T()
(live demo)
You can probably observe the same result before C++17 because compilers have always tried to optimise return values. Even in your standard, C++98, you can probably observe that the copy constructor isn't invoked in the first case.
But, hey, none of that is relevant for a simple arithmetic expression.
Related
#include <iostream>
#include <coroutine>
class eager {
public:
struct promise_type {
promise_type() { std::cout << "promise_type ctor" << std::endl; }
~promise_type() { std::cout << "~promise_type dtor" << std::endl; }
struct return_object {
return_object() { std::cout << "return_object ctor" << std::endl; }
~return_object() { std::cout << "~return_object dtor" << std::endl; }
operator eager() { return {}; }
};
auto get_return_object() noexcept { return return_object{}; }
constexpr auto initial_suspend() const noexcept { return std::suspend_never{}; }
constexpr auto final_suspend() const noexcept { return std::suspend_never{}; }
constexpr auto return_void() const noexcept {}
auto unhandled_exception() -> void { throw; }
};
};
auto coroutine() -> eager {
co_return;
}
auto main() -> int
{
coroutine();
return 0;
}
You can see the result for MSVC, clang and GCC here: https://godbolt.org/z/Yan9s9TPE
According to lots of articles about coroutine, the coroutine() will be transformed into...
auto coroutine() -> eager {
eager::promise_type promise;
auto res = promise.get_return_object();
// initial suspend
promise.return_void();
// final suspend
return res;
}
At a glance, since the promise object is constructed first, I thought it would be the last object to be destructed.
However, MSVC and GCC show reverse order:
// from MSVC/GCC
promise_type ctor
return_object ctor
~promise_type dtor
~return_object dtor
On the other hand, clang shows what I expected:
// from clang
promise_type ctor
return_object ctor
~return_object dtor
~promise_type dtor
Which one is right?
Or, is the destruction order of promise object and return object just unspecified by standard?
According to lots of articles about coroutine
Then "lots of articles about coroutine[sic]" are incorrect.
The result object is not on the coroutine stack. It cannot be on the coroutine stack, because it's the result object for the initial call to the coroutine.
All that the C++ standard says about get_result_object is this:
The expression promise.get_return_object() is used to initialize the glvalue result or prvalue result object of a call to a coroutine.
The call to get_return_object is sequenced before the call to initial_suspend and is invoked at most once.
It happens before initial_suspend and it gets called once. That's all it has to say. Therefore, everything else about result objects from functions work as normal; in this case, it simply gets initialized before the function properly starts instead of when the function is about to return.
By C++'s normal rules, a function's result object is on the caller's stack, not the stack of the function being called. So when promise.get_result_object() is evaluated, it is initializing storage provided by the caller.
main discards the result of the expression coroutine(). This means that it will manifest a temporary from the prvalue result object, and the type of this temporary will be eager. The temporary will be destroyed, but only after control returns to main.
Here's the tricky part: the return prvalue from get_result_object() is not eager. It's eager::promise::result_object. Initializing the return value requires performing an implicit conversion from result_object to eager. This requires manifesting a temporary of type result_object to perform that conversion on.
The standard rule for destroying temporaries is:
Temporary objects are destroyed as the last step in evaluating the full-expression ([intro.execution]) that (lexically) contains the point where they were created.
But... what is the "full-expression" here?
One would assume it would be the promise.get_result_object() expression. But is that a "full-expression" by C++'s rules? These rules are rather esoteric and technical. One could argue that promise.get_result_object() is being used to initialize an object and therefore it is de-facto an "init-declarator". But "init-declarator" is a piece of grammar, and promise.get_result_object() is not stated by the text to be an "init-declarator".
An argument could be made that the only expression that is certainly a full expression is coroutine(). And therefore, one could make the argument that any temporaries used to initialize the return value object should persist until control returns to the caller.
I would argue that the standard wording is under-specified and therefore both versions are equally legitimate until clarification is provided. Clang's version makes more sense (but not for the reasons you claim), but the others are at least arguable.
I found that there is a different execution order between two similar statements(the only difference is the below one has an additional ;). The destructor order is different. Does C++ have a corresponding specification about that or it's only an unspecified behavior?
Environment: GCC10
#include <iostream>
template <int num>
struct S {
S() {std::cout << "S(" << num << ")\n"; }
~S() {std::cout << "~S(" << num << ")\n"; }
};
int main() {
({S<1>(), S<2>();});
std::cout << "-----------------------------------\n";
({S<3>(), S<4>();;});
}
output:
S(1)
S(2)
~S(1)
~S(2)
-----------------------------------
S(3)
S(4)
~S(4)
~S(3)
This is not standard C++. This is a GCC extension known as statement expression. A compound statement enclosed in parentheses can appear where an expression is allowed. If the last statement in the brace-enclosed block is an expression statement, then the value of this expression is also the value of the overall statement expression; otherwise, the statement expression is of type void and has no value.
Your first example is roughly equivalent to
([](){ return S<1>(), S<2>(); })();
(that's a lambda that's created and then called immediately). There's a comma expression that creates S<1> and S<2> temporaries. S<1> is destroyed, S<2> is, technically, copied to the return value - but that copy is elided. If it weren't for this copy elision, you'd see
S<1>()
S<2>()
S<2>(S<2>&&) // (1) move constructor
~S<2>() // (2) the original temporary is destroyed
~S<1>()
~S<2>() // the copy is destroyed outside of the lambda
But the pair (1)/(2) is elided, leaving the sequence you observe in your example.
In the second example, the last statement within the braces is not an expression, so the whole thing doesn't have a value either. It's roughly equivalent to
([](){ S<3>(), S<4>(); return; })();
Both temporaries are created and destroyed within the lambda, and the usual rules apply - temporaries are destroyed in the reverse order of construction.
this is example inspired by example from cppreference
struct S {
operator int() { throw 42; }
};
int main(){
variant<float, int> v{12.f}; // OK
cout << std::boolalpha << v.valueless_by_exception() << "\n";
try{
v.emplace<1>(S()); // v may be valueless
}
catch(...){
}
cout << std::boolalpha << v.valueless_by_exception() << "\n";
}
For one compiler I tried it outputs
false, true
meaning that emplace caused the variant to become valueless
What I do not understand is how this happened.
In particular I do not understand why emplace is called at all, I would expect the program to not even call it since conversion from S to int argument throws.
Note the signature for the relevant std::variant::emplace overload:
template <size_t I, class... Args>
std::variant_alternative_t<I, variant>& emplace(Args&&... args);
It takes a pack of forwarding references. This means that the conversion operator from S to int is not called when evaluating the function arguments; it's called inside the body of emplace. Since trying to construct the int in place would then fail, the variant is made valueless by exception.
It could perhaps be possible to implement variant such that for trivially movable types, the old value is saved before in place construction is attempted, and then restored if it failed, but I'm not sure if it fits in with the various restrictions on the type's implementation given by the standard.
Why does this code compile with GCC (4.9 and 5+), but not with clang (3.5-3.9)?
void test(const int&) { }
int main() {
const int x = 42;
auto f = []{ test(x); };
}
I have some vague idea that the discrepancy has to do with ODR (One Definition Rule) usage, but I don't understand that well enough to figure out what's going on here.
x is odr-used because it's bound to a reference (test's parameter). It therefore must be captured ([expr.prim.lambda]/13):
If a lambda-expression or an instantiation of the function call
operator template of a generic lambda odr-uses ([basic.def.odr]) this
or a variable with automatic storage duration from its reaching scope,
that entity shall be captured by the lambda-expression.
Violations of this rule, like all other rules in the standard that doesn't say "no diagnostic required" or "undefined behavior", require a diagnostic.
GCC, unfortunately, performs constant folding too early, before it could tell whether it's an odr-use or not. This can lead to problems such as [&]()->const int & { return x; } returning a dangling reference.
T.C. has the right diagnosis, here's a clearer bit of legal code where clang does the right thing and gcc doesn't:
#include <iostream>
void test(const int&a) { std::cout << "in test() -- " << &a << "\n"; }
int main() {
const int x = 42;
std::cout << "in main() -- " << &x << "\n";
auto f = [&]{ test(x); };
f();
}
gcc prints different addresses for a capture-by-reference variable than the original!
Why does the following compile in GCC 4.8 (g++)? Isn't it completely ill-formed?
void test(int x)
{
return test(3);
}
int main() {}
I'm trying to use the result of calling test, which does not exist
I'm trying to return a value from test
Both should be fundamentally impossible — not just UB, as far as I can recall — with a void return type.
The only warning I get is about x being unused, not even anything about a non-standard implicit return type being added.
Live demo
That's allowed by the standard (§6.6.3/3)
A return statement with an expression of type void can be used only in functions with a return type of cv void; the expression is evaluated just before the function returns to its caller.
As to why GCC allows it - sure because the Standard requires it to be valid. Building the transitive closure to the rationale of the rule in the Standard, I'm pretty sure that GCC allows this because it's useful in the event of templates
template<typename F>
typename std::result_of<F()>::type call(F f) {
return f();
}
int main() {
std::cout << call([]{ return 42; }) << std::endl;
call([]{ std::cout << "I'm just an outputtor!" << std::endl; });
}
As you see, call did not need to do a special case for void in the return statement. Sort of similar to how x.~T() is allowed even if T ends up as int.