What's difference between these codes and why do I have a warning in the second code?
warning: expression with side effects has no effect in an unevaluated context
struct A
{ };
struct B : A
{ };
int main(){
A* temp = new A();
A* temp1 = new B();
std::cout << "B==A : " << (typeid(temp1) == typeid(temp)) << std::endl;
return 0;
}
// .. above code changed just one line:
std::cout << "B==A : " << (typeid(temp1) == typeid(new A())) << std::endl;
I would also like some explain about the warning?
CodePudding user response:
There is no point in writing typeid(new A())
. It is just a more complicated way of writing typeid(A*)
.
But typeid(new A())
may look as if it will create a new A
object and call its constructor. The expression is however evaluated only if it is a glvalue of polymorphic type, which it isn't here. It is difficult to quickly recognize whether or not the expression is a glvalue of polymorphic type and therefore the compiler may warn you in either case about it if the expression would have side effects. (At least that seems to be what GCC does.)
Furthermore typeid(temp1) == typeid(temp)
is also pointless. This simply compares the declared types of the two variables since they are pointer types and will always result in true
, because both temp1
and temp
are of type A*
.
Maybe you meant to do typeid(*temp1) == typeid(*temp)
. But that will also always result in true
here, since A
is not a polymorphic type. (It doesn't have any virtual functions.)
CodePudding user response:
Without going into the full description of what constitutes a glvalue expression, it is clear from your code that A
is not a polymorphic class; so, for the purposes of the excerpt below, the expression new A()
is clearly not, "a glvalue of a polymorphic class type."
Thus, from this Draft C Standard, we can see that that expression will not be evaluated (bold emphasis mine):
8.5.1.8 Type identification [expr.typeid]
…
3 Whentypeid
is applied to an expression other than a glvalue of a polymorphic class type, the result refers to astd::type_info
object representing the static type of the expression. Lvalue-to-rvalue (7.1), array-to-pointer (7.2), and function-to-pointer (7.3) conversions are not applied to the expression. If the expression is a prvalue, the temporary materialization conversion (7.4) is applied. The expression is an unevaluated operand (8.2).
The compiler is warning you that the new A()
expression will not be evaluated. This may not seem important, in the code that you have shown, but may become relevant if your A
constructor does something that changes the running environment, like modifying a static
class member: For example, add a static int count
variable to A
, initialized to zero, and increment that in the A
constructor; printing the value of that counter at the end of the main
illustrates the issue:
#include <iostream>
struct A {
static int count;
A() { count; }
};
struct B : A {
};
int A::count{ 0 };
int main()
{
std::cout << A::count << std::endl; // 0
A* temp1 = new B(); // Calls A c'tor: count now 1
std::cout << A::count << std::endl; // 1
std::cout << "B==A : " << (typeid(temp1) == typeid(new A())) << std::endl; // No c'tor call!
std::cout << A::count << std::endl; // count STILL 1
return 0;
}