Skip to content

Comments

solution: rvalues respect polymorphism#2

Open
isc30 wants to merge 1 commit intoamarmer:masterfrom
isc30:patch-2
Open

solution: rvalues respect polymorphism#2
isc30 wants to merge 1 commit intoamarmer:masterfrom
isc30:patch-2

Conversation

@isc30
Copy link

@isc30 isc30 commented Sep 12, 2018

@amarmer
Copy link
Owner

amarmer commented Sep 12, 2018

Great!

There is also similar solution:

const X& x = (i == 0)? (const X&)X0() : (i == 1)? (const X&)X1() : (const X&)X2();

pX = const_cast<X*>(&x);

@isc30
Copy link
Author

isc30 commented Sep 12, 2018

I need to say that those solutions are relying on undefined-ish behavior (casting X0&& to X&& and retaining the ownership) and not every compiler accepts them (see GCC).
If I encountered this case at work, I would use the placement new instead

@amarmer
Copy link
Owner

amarmer commented Sep 12, 2018

It seems that it is not yet fixed in GCC.

Explanation why it should work:

These are introduced in C++ 11 (all compilers support it):
const X0& x = X0();
and
X0&& x = X0();

Then this should and works as well in all compilers:
X0&& x = (X0&&)X0();

Then this should work, because there is no difference from the above (but it only works in the latest Clang 8.0.0):
X0&& x = (true)? (X0&&)X0() : (X0&&)X0();

Then:
X&& x = (true)? (X0&&)X0() : (X0&&)X0();

Then:
X&& x = (true)? (X&&)X0() : (X&&)X0();

And finally:
X&& x = (true)? (X&&)X0() : (X&&)X1();

In VS 17 it works only with const X&.

@isc30
Copy link
Author

isc30 commented Sep 12, 2018

so you think this is actually a bug in GCC?

as curiosity: I implemented a small PoC for stack_unique_ptr
https://wandbox.org/permlink/9LK3GNbs1QT34YGX

@amarmer
Copy link
Owner

amarmer commented Sep 12, 2018

Yes, if my conclusions are correct, it is a bug in GCC, and also because it is fixed in Clang 8.0.0 and especially because of https://twitter.com/isocpp/status/1039615649759211520, post from Richard Smith :-)

@isc30
Copy link
Author

isc30 commented Sep 13, 2018

Attaching interesting info, seems like expression trees using rvalues (in general) are badly supported in GCC:
https://stackoverflow.com/questions/34901154/dynamic-cast-and-rvalue-reference
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69390

@cgraeser
Copy link

The problem with gcc shows up without r-value references as well. For the following code snippet
clang prolongs the lifetime of the X0 temporary and calls X0~ at the end of the scope. In contrast
gcc (at least 7.2) calls X0~ during the initialization of x before printing 1. I.e. it looks like the polymorphic type of actual object on the stack is X0 for clang and X for gcc. This is consistent with the 'call to pure virtual method' runtime error with gcc when calling x.Process() (after const ifying Process)

  {
    const X& x = (const X0&) X0();
    std::cout << "1" << std::endl;
  }
  std::cout << "2" << std::endl;

BTW: Casting away constness is IMHO a no-go.

@isc30
Copy link
Author

isc30 commented Sep 13, 2018

Agree with the casting away const ness is IMHO a no-go, its too hacky... but this is a puzzle 😆

The problem in GCC starts when casting rvalue (X0&&, X1&&. X2&&) to X&& or const X&. At this point, the lifetime of the instance gets messed up depending on the compiler version: sometimes resolves to X instead of X0, sometimes the destructor is incorrectly called, others you carry a reference to a temporary, etc.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants