• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.
Sign in to follow this  
Followers 0
Tispe

Attaching a std::shared_ptr to a void* member

11 posts in this topic

Hi

 

I am having trouble attaching a std::shared_ptr to a void* member inside a struct for the Enet library. The netevent.peer->data member is of type void*, I want to be able to create a shared_ptr and set it to netevent.peer->data. When I recieve packets I can cast netevent.peer->data back to a shared_ptr and get the members out. But all the tricks i've tried so far has crashed the application.

 

Any input?

case ENET_EVENT_TYPE_CONNECT:
	{
		char buffer[64];
		in_addr addr;
		long long ipandport = (netevent.peer->address.host << 16) | netevent.peer->address.port;		//Unique ID
		std::shared_ptr<PeerData> spNewPeer(new PeerData);
		spNewPeer->ipandport = ipandport;
		spNewPeer->peer = netevent.peer;
		addr.S_un.S_addr = netevent.peer->address.host;
		sprintf_s(buffer, "%s:%d", inet_ntoa(addr), netevent.peer->address.port);
		printf("A new client connected from %s.\n", buffer);
		spNewPeer->sipandport = string(buffer);
		netevent.peer->data = &(*spNewPeer);						//assigning, might be bad....
		cout << "Registered user: " << ipandport << endl;
		break;
	}
case ENET_EVENT_TYPE_RECEIVE:
	{
		std::shared_ptr<PeerData> spPeer(netevent.peer->data);
		cout << "A packet of length " << netevent.packet->dataLength 
			<< " containing " << netevent.packet->data 
			<< " was received from " << spPeer->sipandport			//causes compile errors, cannot convert parameter 1 from 'void *' to 'PeerData *'
			<< " on channel" << netevent.channelID << "." << endl;

		if(netevent.packet != NULL){
			enet_packet_destroy (netevent.packet);
		}
		break;
	}
0

Share this post


Link to post
Share on other sites
Not to mention that a shared_ptr to void* doesn't make much sense. A void* is just a pointer, not the actual data pointed to by the pointer, and it's trivial to copy/share the pointer itself. shared_ptr is for holding on to a resource with indeterminate lifetime, typically managed via a destructor and RAII.

Sounds like what you want is to have a void* point into a buffer that is managed by some other logic, which is a totally different beast, and probably not actually compatible with the library you're using.
2

Share this post


Link to post
Share on other sites

 

I want to be able to create a shared_ptr and set it to netevent.peer->data. When I recieve packets I can cast netevent.peer->data back to a shared_ptr and get the members out. But all the tricks i've tried so far has crashed the application.


Okay, there are several major problems here:
First, you cannot send a pointer to an object. As an example, imagine I sold an item to you. Instead of packaging the item in a box and shipping it, I mail you the location of where the item is in my house. What good does knowing where the item is in my house help you? This is essentially sending a pointer to an object. Instead, you'll need to package the object (via serialization) and send it out. If you need to refer to this object over the network later, use a unique identifier (such as an integer) to refer to the object on both machines.

Second, you cannot send a shared pointer as it is over the network, for the same reasons given above. A shared pointer is basically an integer keeping track of the number of references, and the object its pointing to. If you were to somehow send both the object and the reference count, how do the machines synchronize the reference count? Why does one machine care about the other's memory management?

 

 

I think you need to reread my original post. The peer->data member is never sent anywhere. It is just a pointer in the peer object where the application can put data.

 

 

Not to mention that a shared_ptr to void* doesn't make much sense. A void* is just a pointer, not the actual data pointed to by the pointer, and it's trivial to copy/share the pointer itself. shared_ptr is for holding on to a resource with indeterminate lifetime, typically managed via a destructor and RAII.

Sounds like what you want is to have a void* point into a buffer that is managed by some other logic, which is a totally different beast, and probably not actually compatible with the library you're using.

 

What about having the void* point to a shared_ptr? peer->data->spMyPointer->MyMember? Will the shared_ptr keep reference count and not delete itself for this method?

0

Share this post


Link to post
Share on other sites

Added an std::map to own the shared_ptr but on the second packet the application crashes. It works once, then crash .... Getting an access violation.

The statement std::shared_ptr<PeerData> spPeer((PeerData*)netevent.peer->data); results in an spPeer with unvalid members.

std::map<long long, std::shared_ptr<PeerData>> AllPeers;
bool loop = true;
while(loop){
	ENetEvent netevent;
	/* Wait up to 1000 milliseconds for an event. */
	if(enet_host_service (server, &netevent, 10)){
		switch (netevent.type)    {    
		case ENET_EVENT_TYPE_CONNECT:
			{
				char buffer[64];
				in_addr addr;
				long long ipandport = netevent.peer->address.host;
				ipandport = (ipandport << 16) | netevent.peer->address.port;		//Unique ID
				std::shared_ptr<PeerData> spNewPeer(new PeerData);
				spNewPeer->ipandport = ipandport;
				spNewPeer->peer = netevent.peer;
				addr.S_un.S_addr = netevent.peer->address.host;
				sprintf_s(buffer, "%s:%d", inet_ntoa(addr), netevent.peer->address.port);
				printf("A new client connected from %s.\n", buffer);
				spNewPeer->sipandport = string(buffer);
				netevent.peer->data = spNewPeer.get();								//assigning, might be bad....
				cout << "Registered user: " << ipandport << endl;
				AllPeers[ipandport] = spNewPeer;
				break;
			}
		case ENET_EVENT_TYPE_RECEIVE:
			{
				std::shared_ptr<PeerData> spPeer((PeerData*)netevent.peer->data);
				cout << "A packet of length " << netevent.packet->dataLength 
					<< " containing " << netevent.packet->data 
					<< " was received from " << spPeer->sipandport			//causes compile errors, cannot convert parameter 1 from 'void *' to 'PeerData *'
					<< " on channel" << netevent.channelID << "." << endl;

				if(netevent.packet != NULL){
					enet_packet_destroy (netevent.packet);
				}
				break;
			}
Edited by Tispe
0

Share this post


Link to post
Share on other sites

You should take a step or three back.

 

 

First, understand the purpose and intended use cases of shared_ptr. What you're doing here makes zero sense, and it's clear you're not familiar with how RAII works or how object lifetimes work or even how shared memory management works.

 

Second, think carefully about the way you use anything related to void pointers. They are dangerous, tricky, and easy to cause bugs with. Avoid them if at all possible.

 

Third, please at least make an effort to describe the problem you're trying to solve instead of just posting code that can't possibly be used to reproduce your problem and expecting people to magically figure it out.

2

Share this post


Link to post
Share on other sites

std::shared_ptr<PeerData> spPeer((PeerData*)netevent.peer->data);


When you construct a shared pointer from a raw pointer, the shared pointer assumes ownership of the pointer. See the sample code below:
#include <memory>

int main(int,char*[]) {
    typedef std::shared_ptr<int> SharedInt;
    void* ptr;
    
    SharedInt a(new int);
    /*1*/ {
        ptr = &(*a);
    }
    
    /*2*/ {
        SharedInt b( (int*)ptr );
        *b = 5;
    } // b is destroyed, ptr is deleted, and a is dangling
} // Crash once a is destroyed
Edited by fastcall22
2

Share this post


Link to post
Share on other sites

You should take a step or three back.

 

 

First, understand the purpose and intended use cases of shared_ptr. What you're doing here makes zero sense, and it's clear you're not familiar with how RAII works or how object lifetimes work or even how shared memory management works.

 

Second, think carefully about the way you use anything related to void pointers. They are dangerous, tricky, and easy to cause bugs with. Avoid them if at all possible.

 

Third, please at least make an effort to describe the problem you're trying to solve instead of just posting code that can't possibly be used to reproduce your problem and expecting people to magically figure it out.

 

I wanted to do the same as described in this tutorial (http://www.linuxjournal.com/content/network-programming-enet?page=0,1) but using a shared_ptr instead of raw pointer. The tutorial uses malloc() and free() on the peer->data. I just wanted to avoid leaks and use shared_ptr.

case ENET_EVENT_TYPE_RECEIVE:
	if (event.peer->data == NULL) {
		event.peer->data = malloc(strlen((char*) event.packet->data)+1);
		strcpy((char*) event.peer->data, (char*) event.packet->data);

		sprintf(buffer, "%s has connected\n", (char*) event.packet->data);
case ENET_EVENT_TYPE_DISCONNECT:
	sprintf(buffer, "%s has disconnected.", (char*) event.peer->data);
	packet = enet_packet_create(buffer, strlen(buffer)+1, 0);
	enet_host_broadcast(server, 1, packet);
	free(event.peer->data);
0

Share this post


Link to post
Share on other sites

 

std::shared_ptr<PeerData> spPeer((PeerData*)netevent.peer->data);

When you construct a shared pointer from a raw pointer, the shared pointer assumes ownership of the pointer. See the sample code below:
#include <memory>

int main(int,char*[]) {
    typedef std::shared_ptr<int> SharedInt;
    void* ptr;
    
    SharedInt a(new int);
    /*1*/ {
        ptr = &(*a);
    }
    
    /*2*/ {
        SharedInt b( (int*)ptr );
        *b = 5;
    } // b is destroyed, ptr is deleted, and a is dangling
} // Crash once a is destroyed

 

Thanks, got it working now. Here is all the code, which is now working. If you got any comments/improvements let me know ;)

struct PeerData {
	DWORD Status;
	long long ipandport;
	ENetPeer* peer;
	string sipandport;
};

int Server(){
	if (enet_initialize () != 0){
		cout << "An error occurred while initializing ENet.\n";
		enet_deinitialize();
		return EXIT_FAILURE;
	}

	ENetAddress address;
	ENetHost * server;
	/* Bind the server to the default localhost.     */
	/* A specific host address can be specified by   */
	/* enet_address_set_host (& address, "x.x.x.x"); */
	address.host = ENET_HOST_ANY;
	/* Bind the server to port 1234. */
	address.port = 1234;
	server = enet_host_create (& address /* the address to bind the server host to */,                              
		32      /* allow up to 32 clients and/or outgoing connections */,                              
		2      /* allow up to 2 channels to be used, 0 and 1 */,                              
		0      /* assume any amount of incoming bandwidth */,                              
		0      /* assume any amount of outgoing bandwidth */);
	if (server == NULL){    
		cout << "An error occurred while trying to create an ENet server host.\n";    
		return EXIT_FAILURE;
	}

	//Main Loop
	std::map<long long, std::shared_ptr<PeerData>> AllPeers;
	bool loop = true;
	while(loop){
		ENetEvent netevent;
		/* Wait up to 1000 milliseconds for an event. */
		if(enet_host_service (server, &netevent, 10)){
			switch (netevent.type){    
			case ENET_EVENT_TYPE_CONNECT:
				{
					char buffer[64];
					in_addr addr;
					long long ipandport = netevent.peer->address.host;
					ipandport = (ipandport << 16) | netevent.peer->address.port;		//Unique ID
					std::shared_ptr<PeerData> spNewPeer(new PeerData);
					spNewPeer->ipandport = ipandport;
					spNewPeer->peer = netevent.peer;
					addr.S_un.S_addr = netevent.peer->address.host;
					sprintf_s(buffer, "%s:%d", inet_ntoa(addr), netevent.peer->address.port);
					printf("A new client connected from %s.\n", buffer);
					spNewPeer->sipandport = string(buffer);
					netevent.peer->data = spNewPeer.get();
					cout << "Registered user: " << ipandport << endl;
					AllPeers[ipandport] = spNewPeer;
					break;
				}
			case ENET_EVENT_TYPE_RECEIVE:
				{
					cout << "A packet of length " << netevent.packet->dataLength 
						<< " containing " << netevent.packet->data 
						<< " was received from " << ((PeerData*)netevent.peer->data)->sipandport
						<< " on channel " << int(netevent.channelID) << "." << endl;

					if(netevent.packet != NULL){
						enet_packet_destroy (netevent.packet);
					}
					break;
				}
			case ENET_EVENT_TYPE_DISCONNECT:        
				printf("%s disconected.\n", ((PeerData*)netevent.peer->data)->sipandport.c_str());        
				AllPeers.erase(((PeerData*)netevent.peer->data)->ipandport);  
				netevent.peer->data = NULL;    
			}
		}
	}

	//Reset all peers

	enet_host_destroy(server);
	enet_deinitialize();
	return 0;
}
0

Share this post


Link to post
Share on other sites

Uhm... you realize that if you'd simply use a map<long long, PeerData> you would have exactly the same result? Why are you so hell bent on getting a shared_ptr involved when it's absolutely pointless? This feels a lot like "new toy syndrome".

 

In fact, it would even simplify things, as your PeerData only uses the default constructor and a map will automatically create a default constructed object if necessary.

 

PeerData* data = &AllPeers[ipandport]; will do exactly the same, without abusing the map as an artificial crutch way to keep your shared_ptr alive.

0

Share this post


Link to post
Share on other sites

Uhm... you realize that if you'd simply use a map<long long, PeerData> you would have exactly the same result? Why are you so hell bent on getting a shared_ptr involved when it's absolutely pointless? This feels a lot like "new toy syndrome".

 

In fact, it would even simplify things, as your PeerData only uses the default constructor and a map will automatically create a default constructed object if necessary.

 

PeerData* data = &AllPeers[ipandport]; will do exactly the same, without abusing the map as an artificial crutch way to keep your shared_ptr alive.

 

The std::map was intended to be implemented regardless. I want to be able to group peers in different groups later. For example if 3 players are on Team1, the shared_ptr would be placed in a new std::map called Team1. Then I can let Team1 chat with eachother by just traversing that container.

 

I also want an std::map that states which connected peers are "Authenticated", such that non-Authenticated peers can be filtered.

 

All of these containers would hold the same shared_ptr, but they will be used for different purposes.

 

Question, map<long long, PeerData>, would the PeerData object be on the stack or the heap?

Edited by Tispe
0

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0