Jump to content
  • Advertisement
Sign in to follow this  
InvalidPointer

Fun With C++ [Beginners Stay Away, Lest Ye Be Corrupted]

This topic is 3051 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Have more time off today, and decided I'd test an interesting little idiom out to help with const-correctness. It turns out you can actually do a lot of neat (and admittedly very dangerous) tricks with placement new, up to and including re-instantiating objects using the this pointer. As far as I can tell, there do not appear to be any adverse effects so long as the idiom itself is used correctly; since we're using the this pointer from an already-constructed object we're guaranteed to have proper alignment and size and recreating the object in this fashion doesn't appear to muck up any lifetimes, etc. Code: main.cpp
#include "SomeClass.h"
#include <iostream>

int main()
{
	{
		SomeClass stackClass;
		stackClass.ReInstantiate();
		stackClass.WriteSomeData();
	}

	std::cout << "---" << std::endl;
	SomeClass* heapPtr = new SomeClass();
	heapPtr->ReInstantiate();
	heapPtr->WriteSomeData();
	delete heapPtr;

	int i;
	std::cin >> i;
	return 0;
}
SomeClass.h:
#pragma once

class SomeClass
{
public:
	SomeClass();
	virtual ~SomeClass();

	void				ReInstantiate();

	void				WriteSomeData();

private:
	char* const			dataChunk;
	const unsigned long		moreData;
	const bool			evenMoreData;
};
SomeClass.cpp:
#include "SomeClass.h"
#include <memory>
#include <iostream>

SomeClass::SomeClass() : dataChunk(new char[32]),
						 moreData(0),
						 evenMoreData(true)
{
	std::cout << "SomeClass()" << std::endl;
}

SomeClass::~SomeClass()
{
	std::cout << "~SomeClass()" << std::endl;
	if(dataChunk)
		delete[] dataChunk;
}

void SomeClass::WriteSomeData()
{
	std::cout << "WriteSomeData()" << std::endl;
	for( size_t i = 0; i < 32; i++ )
	{
		dataChunk = '3';
	}
}

void SomeClass::ReInstantiate()
{
	std::cout << "ReInstantiate()" << std::endl;
	//void* thisPtr = this;
	this->~SomeClass();
	new(this) SomeClass;
}
I would appreciate if someone could test this on something other than MSVC9 (VS2008) to see what happens. No guarantees if it's actually even practical or actually works elsewhere, it just seems interesting.

Share this post


Link to post
Share on other sites
Advertisement
I'm pretty sure I once read an article by Herb Sutter in which he discussed this as a bad idea.

Share this post


Link to post
Share on other sites
Fascinating, but how does it affect const correctness? Anyway, it works on Mingw32 GCC 4.4.0, except for #pragma once.

Share this post


Link to post
Share on other sites
Quote:
Original post by DevFred
I'm pretty sure I once read an article by Herb Sutter in which he discussed this as a bad idea.
You would be referring to GotW #23, which InvalidPointer should have a good read of.

Share this post


Link to post
Share on other sites
Quote:
Original post by iMalc
Quote:
Original post by DevFred
I'm pretty sure I once read an article by Herb Sutter in which he discussed this as a bad idea.
You would be referring to GotW #23, which InvalidPointer should have a good read of.

I actually did manage to dig that up before you posted the link (through the somewhat related GotW #28) and it did validate a few reservations/sticky spots I had regarding inheritance. Obviously, if you call this method on a derived object it's going to die; you aren't even instantiating the same object type! There is something of a workaround, however-- by making the method virtual and fixing types in derived classes it does work correctly. While we're on the subject of bad C++ practice, you could probably even make the ReInstantiate function definition a macro, though I'm sure there might be more esoteric methods of automagically updating this.

Again, no guarantees if it's actually even practical or actually works elsewhere, it just seems interesting.

Share this post


Link to post
Share on other sites
Quote:
Original post by InvalidPointer
There is something of a workaround, however-- by making the method virtual and fixing types in derived classes it does work correctly.

Except the v-table could be destroyed in the destructor meaning a copy would be needed?

Share this post


Link to post
Share on other sites
Quote:
Original post by Moomin
Quote:
Original post by InvalidPointer
There is something of a workaround, however-- by making the method virtual and fixing types in derived classes it does work correctly.

Except the v-table could be destroyed in the destructor meaning a copy would be needed?

I believe that placement new renders that moot, as it just builds a new one anyway. Actually implementing my proposed solution and calling ReInstantiate on a base class pointer seems to work, though again that may just be result of compiler-specific behavior.

EDIT: Never mind, I see what you're getting at now, and no, it wouldn't be an issue. At this point we've already dispatched the recreation method to the right implementation, and we know at compile time what type of class we want to create-- it's 'baked into' the function itself.

Share this post


Link to post
Share on other sites
While it's interesting that it can be done, I agree with Harb Sutter that it shouldn't be done.

Quote:
I still don't see what this has to do with const-correctness.

It allows a reasonable copy constructor/assignment operator to be defined for classes with const member variables (and reference member variables).

Share this post


Link to post
Share on other sites

void SomeClass::ReInstantiate()
{
std::cout << "ReInstantiate()" << std::endl;
//void* thisPtr = this;
this->~SomeClass();
new(this) SomeClass;
}


I wonder: if the constructor by any chance happens to throw, would it mean that the destructor would be called again during stack unwinding?

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!