배열은 어떻게 복사하는가?

생성일
Aug 16, 2023 11:58 PM
태그
무엇을 하다가 알게 되었나? → 그래픽스를 실습하다가.
 
어떤게 문제였나?
→ float 배열의 값 전달이 진행이 되질 않았다.
Example.h Code.
public: // 이름 짓기 규칙 // https://github.com/Microsoft/DirectXTK/wiki/Implementation#naming-conventions ID3D11Device* device; ID3D11DeviceContext* deviceContext; IDXGISwapChain* swapChain; D3D11_VIEWPORT viewport; ID3D11RenderTargetView* renderTargetView; ID3D11VertexShader* vertexShader; ID3D11PixelShader* pixelShader; ID3D11InputLayout* layout; ID3D11Buffer* vertexBuffer = nullptr; ID3D11Buffer* indexBuffer = nullptr; ID3D11Texture2D* canvasTexture = nullptr; ID3D11ShaderResourceView* canvasTextureView = nullptr; ID3D11RenderTargetView* canvasRenderTargetView = nullptr; ID3D11SamplerState* colorSampler; UINT indexCount; int canvasWidth, canvasHeight; float backgroundColor[4] = { 0.8f, 0.8f, 0.8f, 1.0f }; };
main.cpp Code.
float canvasColor[4] = { 0.0f, 0.0f, 0.0f, 1.0f };//TODO: 실습문제용 임시코드 // Main message loop MSG msg = {}; while (WM_QUIT != msg.message) { if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } else { // Start the Dear ImGui frame ImGui_ImplDX11_NewFrame();//TODO: IMGUI 사용 ImGui_ImplWin32_NewFrame(); ImGui::NewFrame(); ImGui::Begin("Background Color"); ImGui::SliderFloat3("RGB(0.0->1.0)", canvasColor, 0.0f, 1.0f); ImGui::End(); ImGui::Render(); example->backgroundColor = canvasColor; example->Update(); example->Render(); ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());//TODO: IMGUI 사용 // switch the back buffer and the front buffer example->swapChain->Present(1, 0); } }
문제의 부분. 분명 example의 background Color와 canvasColor는 동일한 타입의 정적 배열이나. 해당 코드로는 값 전달이 되질 않았다.
물론 backgroundColor[0..1..2..3] = canvasColor[0..1..2..3] 형태로 하나하나 넣어주는 건 가능했지만, 한 번에 값 전달이 되질 않았고 그 이유를 찾아보니.
💻
이 둘 간에 대입 연산을 통해 값을 복사하려고 하고 있습니다. C++에서 배열은 기본적으로 포인터로 작동하므로, 이런 방식으로 배열을 복사하려면 루프를 사용하거나 memcpy와 같은 함수를 사용해야 합니다.
최근 C#과 Java만 사용하니 살짝 c++의 포인터 개념에 대해 망각하고 있었다.
float[] backgroundColor = new float[4]; float[] backgroundColor2 = new float[4]; // Start is called before the first frame update void test() { backgroundColor = backgroundColor2; }
왜냐하면, c#에서는 이런식으로 값 복사가 이루어지기 때문인데 그럼 왜 c#에선 되는지 그 이유를 또 찾아보았다.
💻
C#에서 배열은 참조 형식(Reference Type)으로 다루어진다. 이는 배열 변수가 배열의 데이터 자체가 아닌 데이터를 가리키는 포인터와 유사한 역할을 한다는 것을 의미한다. 따라서 배열 변수를 다른 배열 변수에 할당하면 실제 데이터를 복사하지 않고 배열 데이터의 참조만 복사된다.
즉 c++에서는 보통 배열을 복사할 땐 copy, memcopy, for 등을 사용하여 복사한다고 하는데
분명 기억 속 에선, 포인터로 복사할 수 있다는 기억이 떠올랐고.
 
float* backgroundColor
example->backgroundColor = canvasColor
이렇게 backgroundColor 자체를 포인터 값으로 잡고 canvasColor의 주소값을 받는다면
편하게 사용 할 수 있다는 사실을 알게 되었다.
 
해당 접근 방식의 단점이라고 한다면, 현재 canvasColor와는 크기가 다른 다른 배열의 주소값도
넣을 수 있다는 것이며 이 때, backgroundColor[5]처럼 메모리 침범 문제가 발생할 수 도 있다.
notion image

 
float* c; float d[4] = { 2,3,4,5 }; float f = 10; c = d; cout << c[0] << endl; // 2 cout << c[3] << endl; // 5 cout << c[7] << endl; // 메모리 침범 cout << *c << endl; // 2 c = &f; // 10 cout << *c << endl; // 10