Troble with double pointer memory allocation

Started by
7 comments, last by matt77hias 6 years, 11 months ago

Hi everyone!
So my question should be fairly simple, yet i couldn't seem to find any documentation on the topic.
As seen below, my problem is that i want to create an array of vertex buffers in Direct X 11. From my experience when using double pointers with classes and structs, this memory copy method has always worked out for me since the classes hold the same memory data structure.
Yet when using DirectX own buffer interface, this type of copy does not work and gives me access violation.
Can someone please explain to me why this is and is there a solution to how to store the old information when expanding the current array?


    void BindDataToBuffer(ID3D11Device* gDevice, ID3D11Buffer** &gVertexBufferArray, FBXData &FBX)
	{
		HRESULT hr;

		if (gVertexBufferArray != nullptr)
		{
			ID3D11Buffer** tempBuffer = new ID3D11Buffer*[this->totalSumMeshes + FBX.meshCount];
			tempBuffer = { nullptr };
		
			for (int i = 0; i < this->totalSumMeshes; i++)
			{
				tempBuffer[i] = gVertexBufferArray[i];
			}

			gVertexBufferArray = tempBuffer;

			this->totalSumMeshes += FBX.meshCount;
Advertisement
Yet when using DirectX own buffer interface, this type of copy does not work and gives me access violation.

Which line? tempBuffer = gVertexBufferArray?

🧙

Yet when using DirectX own buffer interface, this type of copy does not work and gives me access violation.

Which line? tempBuffer = gVertexBufferArray?

Yes :) that line! Sorry if i wasn't clear enough

ID3D11Buffer** tempBuffer = new ID3D11Buffer*[this->totalSumMeshes + FBX.meshCount];
tempBuffer = { nullptr };

This isn't safe. It's probably not the actual problem. But ID3D11Buffer does not actually delete it's self.

You're creating data in your heap, and then lost the ability to delete it.

Even if this was correct, this still shouldn't work. Reason at the end.


			for (int i = 0; i < this->totalSumMeshes; i++)
			{
				tempBuffer[i] = gVertexBufferArray[i];
			}

So you're copying pointers into your tempBuffer now.


gVertexBufferArray = tempBuffer;

Not entirely sure what's going on here. This seems utterly redundant.

But anyways...

The function you need to correctly create a buffer in Directx 11 is... CreateBuffer(...) Create buffer will give you I11D3DBuffer objects that have been correctly created and initialized on the device.

I also don't believe that I11D3DBuffer is safe to actually copy, as it's data is typically managed by the Driver.

gVertexBufferArray = tempBuffer; Not entirely sure what's going on here. This seems utterly redundant.

Note the paremeter type: ID3D11Buffer** &gVertexBufferArra

The function you need to correctly create a buffer in Directx 11 is... CreateBuffer(...) Create buffer will give you I11D3DBuffer objects that have been correctly created and initialized on the device.

That is not important here. He just allocates an array of pointers, sets pointers equal to nullptr or some other pointer. Who cares what the type of the pointee is. (The method would be identical if one would use int * instead of ID3D11Buffer *)

🧙

As far as I can see, the piece of code you provide should work.

A small test with "int" (instead of "ID3D11Buffer"). (Note the obvious memory leak as well).


#include <iostream>


typedef int TYPE;


void exchange(TYPE *&values, size_t old_size, size_t extra_size) {
    TYPE *new_values = new TYPE[old_size + extra_size];
    for (size_t i = 0; i < old_size; ++i) {
        new_values[i] = values[i];
    }
    for (size_t i = old_size; i < old_size + extra_size; ++i) {
        new_values[i] = 0;
    }
    values = new_values;
}


int main() {
 TYPE *values = new TYPE[5];


 for (size_t i = 0; i < 5; ++i) {
    values[i] = i+1;
 }
   
 exchange(values, 5, 10);


 for (size_t i = 0; i < 5; ++i) {
    std::cout << values[i];
 }
 for (size_t i = 5; i < 10; ++i) {
    std::cout << values[i];
 }
}

🧙

I solved the problem! Thank you guys! :)
So my solution to the problem was simple, i solely removed the " tempBuffer = { nullptr }; " line.
Solution:


void BindDataToBuffer(ID3D11Device* gDevice, ID3D11Buffer** &gVertexBufferArray, FBXData &FBX)
	{
		HRESULT hr;

		if (gVertexBufferArray != nullptr)
		{
                        ID3D11Buffer** tempBuffer = new ID3D11Buffer*[this->totalSumMeshes + FBX.meshCount];
		
			for (int i = 0; i < this->totalSumMeshes; i++)
			{
				tempBuffer[i] = gVertexBufferArray[i];
			}

			gVertexBufferArray = tempBuffer;

			this->totalSumMeshes += FBX.meshCount;

Explanation:

My concept was to create a vertex buffer array for each mesh loaded into the project.
The meshes was loaded in from a file format i created myself.
So when i loaded in another file, i wanted to expand the existing array in size without overwriting existing stored data.
Since the ID3DBuffer is a virtual class, i needed to create the ID3DBuffer as a double pointer.
Why? When creating with double pointers, you create an array of interface pointers.
So comparing that to simple data types like int* and int**, the int* is structured like int[x] and int** like int[x][y], but because the interface** is virtual we do NOT get buffer[x][y] but we receive buffer[x] because a single pointer only points to the memory location of the object.


int* == int[x];
int** == int[x][y];

ID3DBuffer* == ID3DBuffer;
ID3DBuffer** == ID3DBuffer[x];

With that in note, when transfering the adress of the data between the two buffers, we want to make sure that the newly created temporary buffer is not a null pointer.
Why? Because otherwise the memory of the pointer would just be set to 0 and therefore we can't give it new adresses since it lacks memory locations to store the adresses in.


for (int i = 0; i < this->totalSumMeshes; i++)
    {
        tempBuffer[i] = gVertexBufferArray[i];
    }

And the:


gVertexBufferArray = tempBuffer;

Is because we want the old array to store new array size we created.
Note:
We do NOT want to delete[] the temp array since the old and the new now hold the same adresses.
Deleting will result in doing so for both the arrays.
The deletion of the memory will be set in the end of the program or when you dont need the array anymore.
And in that case we want to use release, not delete.

The line you removed was just replacing the allocated pointer with an anonymous local array.

You definitely do not understand pointers, memory life time and ownership. I would advice you to use standard container like vector and to have a zero new policy ( make_unique is fine ), and no raw pointers, use comptr for dx objects.

You will save you time, performance, simplify design, reduce complexity, and save baby seals :)

and save baby seals

so that the polar bears can eat them :D

🧙

This topic is closed to new replies.

Advertisement