Skip to main content
GameDev.net gamedev.net
🔒 Locked

[C++] Passing array of Data allocated in a function

Started by DeafManNoEars Jan 23, 2007 at 1:19 PM 2 replies 1.4k views
Original Post
DeafManNoEars
DeafManNoEars
Hi all, I have a couple of questions pertaining to the methods I have created for a ShapeFactory I have in my Game Engine. My game engine resides in it's own DLL and was built in VC7.1 as a Multithreaded DLL. My applications which link to it are also built with the same option. My shapefactory class has functions like this: My apps all derive from a base Application Class which holds a pointer to the engine class in the DLL. Say for example My app class has the following two members.
  
SVertex_XYZ_N_T1* m_pVertices;
uint32*           m_puiIndices;

uint32    m_uiNumVerts;
uint32    m_uiNumIndices;
and I want to fill them with data obtained from the shapefactory. Currently I am using the function below to do so.


//Resides in DLL
CreateCuboid( void** ppVerts, uint32** ppIndices, uint32 &numVerts, 
              uint32 &numIndices, VERTEXTYPE vtp, uint16 iTess, bool bInvert )
{
     numVerts = 6*iTess*iTess;
     numIndices = 6*6*(iTess-1)(iTess-1);

     //create dynamic arrays of data
     SVertex_XYZ_N_T1* pVertices = new SVertex_XYZ_N_T1[numVerts];
     uint32* pIndices = new uint32[numIndices];
        // creation data here

     *ppVerts = pVertices;
     *ppIndices = pIndices;
}

//this is called from the application.  Not the DLL
CreateCuboid( &m_pVertices, &n_puiIndices, m_uiNumVerts, m_uiNumIndices,
               VERTTYPE_XYZ_N_T1, 20, false );

Is there a better or preferred method to do what I am trying to accomplish here? Everything works fine, I just don't know how hapy I am about the void pointer and such. Thanks in advance for any and all help or comments. Seth [Edited by - DeafManNoEars on January 23, 2007 4:09:10 PM]
skillfreak
skillfreak
I cannot address all of your questions, however;

Creating memory for a global purpose (not released within the function that created it) creates the possiblity that programmers on the receiving end of that function do not free those resources later.

I would always create a failsafe to be sure that resources are always free'd.

A resource management class is one possibility - where destructors free if not already freed.

There is a good discussion of resource management in the book Effective C++.

(the book just keeps coming into mind for those following recent posts)
^ A recommendation then.
Zahlman
Zahlman
1) You clearly know how to pass by reference, since you're already doing it. So why not do it here? There's nothing preventing you from passing a pointer by reference (as an out-parameter)

2) The type clearly is known, so why would you use void*? Oh, you want to pass a parameter to indicate a type, and the function is reused to create other types of vertices. That's bad. You want to use templates, instead. (Your sample code, BTW, doesn't seem to check the vertex type and always creates the one type - did you oversimplify? :) )

3) A pointer to an array, plus a size count, together spell trouble. They smell like you are managing dynamic arrays yourself. There's really no call for that in C++.

The resulting advice: Store vectors in your class. Pass the vectors by reference (not const, because the creation function wants to modify the contents), letting them be empty to start with.

class Application {  Engine* e;  std::vector<SVertex_XYZ_N_T1> m_vertices;  std::vector<uint32>           m_uiIndices;  Application(Engine* e) : e(e) {    CreateCuboid<SVertex_XYZ_N_T1>(m_vertices, m_uiIndices, 20, false);  }};// Resides in DLLtemplate<typename VertexType>void CreateCuboid(std::vector<VertexType>& verts, std::vector<uint32>& indices, uint16 iTess, bool bInvert) {  // Resize the "dynamic arrays" appropriately. I keep the constants in locals  // in case the main code needs them - I can't see it ;)  int numVerts = 6*iTess*iTess;  int numIndices = 6*6*(iTess-1)*(iTess-1);  verts.resize(numVerts);  indices.resize(numIndices);  // Then create the data here.  // This will probably have to change to make the templating work properly,  // depending on what types are possible and how they're handled. Unfortunately  // I'm not psychic :( Could I see what you're doing?}


Now, that's just the ideal, pretty C++ version. But this has major problems because you're calling across a DLL boundary. However, the original code probably had the same problem: you don't want any chance that an allocation on one side of the boundary could be deallocated, resized etc. on the other side.

Here we could handle that by doing the resizing on the application side, and passing the resized vectors by const reference. (This will make the vector itself const - i.e. its allocated size and capacity - but not the *elements*, which we will be creating.)
DeafManNoEars
DeafManNoEars
That was just a small post with large snippets removed. It was more the general concept that I wanted reassurance that it was incorrect.

Quote:
Original post by Zahlman
But this has major problems because you're calling across a DLL boundary.


As far as I understand (and I am still fairly new to this) my app and DLL should share the same runtime library. I set the following option in both projects: (Multi-threaded DLL (/MD)) in VC7.1. Are there drawbacks to this.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.