Replicate byte array in C++ problem/help

Options
Hi!

I'm trying to replicate a byte array but can' receive it correctly:

My send code is:

        nByte *data = //... fetch from game
	auto size = //... and the length of the data

	auto options = ExitGames::LoadBalancing::RaiseEventOptions();

	photonCloudClient->opRaiseEvent(
		true
		, data
		, size
		, (nByte) NetworkingEventCodes::OrderEventCode
		, options
	);

My receive code is:

        nByte** ppContent = ExitGames::Common::ValueObject<nByte*>(eventContent).getDataAddress();
        short elementsLeft = *ExitGames::Common::ValueObject<nByte*>(eventContent).getSizes();

	// has any data?
	if(ppContent && elementsLeft > 0)
	{
		// *ppContent == NULL       why?
		// ... do something
	}
Any help would be appreciated!

Comments

  • Kaiserludi
    Kaiserludi admin
    edited August 2017
    Options
    Hi @undercover.

    The cause of your problem is this line:
    
    nByte** ppContent = ExitGames::Common::ValueObject<nByte*>(eventContent).getDataAddress();
    
    That code constructs a temporary ValueObject instance and then store the address of a member variable of that instance in ppContent.
    However as that instance is a temporary, it gets destructed at the end of that very same line already, so from that point on ppContent** point to a member of an already destructed object.

    When storing the content for access beyond the lifetime of that object, then you need to retrieve that content by copy like this:
    
    nByte* pContent = ExitGames::Common::ValueObject<nByte*>(eventContent).getDataCopy();
    // ... do something
    ExitGames::Common::MemoryManagement::deallocateArray(pContent); // don't forget to properly clean up your array copy or it will leak!
    
    When you want to retrieve the array by address instead of by copy, then you need to make sure that the lifetime of the object reaches until the end of the scope in which you access it. So in your case instead of a temporary you want to use a local variable:
    
    ExitGames::Common::ValueObject<nByte*> obj = eventContent;
    nByte** ppContent = obj.getDataAddress();
    
    In other scenarios, where you need to access it after the function has returned you may of course need a variable in dynamic memory instead

    However when your byte-array can potentially become big enough to make the costs of copying it relevant, then you might prefer avoiding a new ValueObject instance (which is constructed from eventContent by COPY) all together and to instead directly access eventContent itself (note that the code below stores the cast-result in a local reference to const - if it would call getDataAddess() directly on the cast result instead of the reference, then the compiler would store the cast result in a new temporary object, which would a) mean that we still get a copy and b) getDataAdress() would still be called on a temporary object just like in your original code):
    
    const ExitGames::Common::ValueObject<nByte*>& objRef = static_cast<const ExitGames::Common::ValueObject<nByte*> >(eventContent);
    nByte** ppContent2 = objRef.getDataAddress();
    
  • undercover
    Options
    Thanks a lot! That make much sense!