[Bug c++/86908] New: static_cast(&derivedClassObject)->virtualMehod() calls base version of virtualMethod()
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86908 Bug ID: 86908 Summary: static_cast(&derivedClassO bject)->virtualMehod() calls base version of virtualMethod() Product: gcc Version: unknown Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: fro0m.spam at gmail dot com Target Milestone: --- #include #include #include #include class BaseStrategy{ public: virtual void doIt() { printf("base do it\n"); }; }; class AStrategy : public BaseStrategy { public: void doIt() { printf("A do it\n"); }; }; class BStrategy : public BaseStrategy { public: void doIt() { printf("B do it\n"); }; }; int main() { BaseStrategy strategy; BaseStrategy* strategyPtr = &strategy; strategyPtr->doIt(); new(&strategy) AStrategy; static_cast(&strategy)->doIt(); strategyPtr->doIt(); } Output in gcc 4.9 and gcc 9.0 is base do it base do it A do it the right output must be (according to standard and behavior of MSVC 2015 and clang 6) is base do it A do it A do it
[Bug c++/86908] static_cast(&derivedClassObject)->virtualMehod() calls base version of virtualMethod()
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86908 Kostya Frumkin changed: What|Removed |Added Status|RESOLVED|UNCONFIRMED Version|unknown |9.0 Resolution|INVALID |--- --- Comment #3 from Kostya Frumkin --- (In reply to Jonathan Wakely from comment #1) > No, your program has undefined behaviour. To make it valid you either need > to use std::launder, or use the pointer that is returned by the placement > new. > > The compiler is allowed to assume that the dynamic type of &strategy does > not change (that's why you need to use std::launder). Hi, for example msvc2013 calls base class's virtual method when msvc2015 calls derived class's virtual method. This is developer's mistake which can be predicted by compiler. Few developers know about this behavior. It'd be awesome to see the correct behavior or at least warning that base method is being used after placement new.
[Bug c++/86908] static_cast(&derivedClassObject)->virtualMehod() calls base version of virtualMethod()
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86908 --- Comment #5 from Kostya Frumkin --- (In reply to Jonathan Wakely from comment #4) > (In reply to Kostya Frumkin from comment #3) > > Hi, for example msvc2013 calls base class's virtual method when msvc2015 > > calls derived class's virtual method. > > It's undefined behaviour. Anything can happen. > > > This is developer's mistake which can be predicted by compiler. Few > > developers know about this behavior. > > Using placement new to replace a polymorphic type is not a common idiom, I > don't think it's worth adding a warning about it. Just don't do it. > > > It'd be awesome to see the correct behavior or at least warning that base > > method is being used after placement new. > > GCC's behaviour is already correct. It is best way to get away with heap allocation in many cases. Let's make a warning about undefined behavior.
[Bug c++/86908] static_cast(&derivedClassObject)->virtualMehod() calls base version of virtualMethod()
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86908 --- Comment #8 from Kostya Frumkin --- > Either way you need to placement new the original type back again, otherwise > the wrong destructor gets called on scope exit, which adds more undefined > behaviour. There should not be undefined behavior because the size of both classes is same and destructors executes same code (in the case it is noop). So the memory to be freed up is same. The behavior must be defined by ISO committee because it is counterintuitive when the base methods are being called. (where to ask?) At the same time this design pattern (strategy) with placement-new is more efficient than with common new. So it has no rationale if the base methods are used when using placement-new. At the same time other compilers generates code where the derived method is callsed after placement-new. So I see two ways: - Ask the community to define behavior. or - Define behavior in gcc itself.