I would opt against using a huge array ([4096]) to store objects. Not only is that wasteful but it's not a very elegant solution either. You also probably don't want to try to store objects in user-created memory unless you've written your own memory manager and you've proven (through testing) that it outperforms the C++ runtime's default memory management.
Instead you should create a data-driven rendering system which you feed render operations. Swiftcoder has made a lot of very good posts about this and is in fact the person who introduced me to the concept. Essentially, you'd want something like this:
[source lang="cpp"]// Some C++-ish pseudo-code; don't use verbatimclass RenderOp{public: Mesh* pMesh; Material* pMaterial; // add whatever else you need };class RenderOpBatch{protected: SomeCollectionType<RenderOp> renderOps;};class Renderer{public: void Draw( const RenderOp op );protected: RenderOpQueue* queue;};[/source]
That's not any sort of working implementation, but hopefully it conveys the point. You can use this to sort, batch and arrange to your heart's content. You can use collection types already found in the standard C++ libraries or you can write custom ones. For instance what I'm doing is creating a custom type called "RenderOpBatch" that allows me to batch render operations. For example, I might want to do a batch for all the parts of a rigged/skinned biped mesh and transmit information for it to the proper shaders/fragments. Batches are pushed into another custom collection type, a "BatchQueue".... however, unlike a standard queue type it allows you to select between LIFO, FIFO and custom sorting arrangements. With a little effort you can implement the same thing.
One thing is for sure: you don't want objects to be responsible for drawing themselves. This makes your engine code hideous, bloated and virtually impossible to port to or support multiple platforms. Defer that work to the renderer as described above. You can be creative in how you strip render operation data from objects, scenes/nodes, etc. Just stick to the data-driven philosophy and you will be a much happier programmer in the end.
EDIT:Also, as someone else mentioned, do not store entire objects in memory within arrays, lists, collections, etc... Store only the pointer to it. Otherwise, you're duplicating (potentially) a LOT of data; plus, modifying one instance in one set of memory will not reflect the changes in another... and any type of sorting/moving operation requires a LOT of extra work for the CPU. Remember that the CPU moves data fastest when it comes in chunks that match the native size of the registers (e.g., 32-bit chunks for x86, 64-bit chunks for x64). So storing the pointers to objects in your array/list/collection can be a marked optimization, as pointers will naturally match the optimal native data size.
Edited by ATC, 23 September 2012 - 04:39 PM.