1

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?

Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
H.M
  • 425
  • 2
  • 16
  • 1
    Your compiler is trying to tell you that the `new A()` will never be executed when you run your program. – tkausl Mar 23 '22 at 17:57
  • @tkausl thx , but why !? it's optimization rules? can I disable that? how? and why first code is working too , just stored in variable(pointer). – H.M Mar 23 '22 at 17:59
  • 3
    Because typeid is a `unevaluated context` as the warning says. It looks at the type of the expression but it never results in code being generated. – tkausl Mar 23 '22 at 18:00
  • 3
    What is your intention with `typeid(new A())`? Why not just `typeid(A*)`? – user17732522 Mar 23 '22 at 18:01
  • @tkausl technically, `typeid` is not fully unevaluated -- it's contextually dependent. If it's evaluating a function that returns a polymorphic type, it actually _does_ generate code and evaluate the expression so that it can determine the concrete type at runtime. – Human-Compiler Mar 23 '22 at 20:31

2 Answers2

3

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.)

user17732522
  • 53,019
  • 2
  • 56
  • 105
3

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     When typeid is applied to an expression other than a glvalue of a polymorphic class type, the result refers to a std::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;
}
Adrian Mole
  • 49,934
  • 160
  • 51
  • 83