그냥 게임개발자

memcpy() 본문

C++ 나만의 복습

memcpy()

sudoju 2024. 4. 7. 18:09

깊은복사 얕은복사 들어봤을 거다.

 

깊은 복사(Deep Copy)는 새로운 공간을 확보해 아예 복사해버려서 새로운 것이 생겨서 값을 바꿔도 원본은 변하지 않음

얕은 복사(Shallow Copy)는 메모리 주소값만 복사해서 값을 변경하면 원본 값도 변경이되는 것

 

 

memcpy()

memcpy()는 어떤 변수의 메모리에 있는 값들을 다른 변수의 "특정 메모리값"으로 복사할 때 사용

Array을 깊은 복사할 때 쓰인다.

 

문법은 아래와 같다.

void* memcpy(void* destination, const void* source, size_t num);

 

#include <iostream>
#include <string>

using namespace std;

int main()
{
    int v[3] = {1, 2, 3};
    int ret[3];
    
    memcpy(ret, v, sizeof(v));
    
    cout << ret[1] << '\n';
    
    ret[1] = 100;
    
    cout << ret[1] << '\n';
    cout << v[1] << '\n';
    
    return 0;
}

ret의 1번째 값은 바뀌었는데 v의 첫번째 값은 바뀌지 않은 것을 볼 수 있다.

이렇듯 제대로 깊은 복사가 되어서 ret을 아무리 수정하더라고 v는 수정이 되지 않는 것을 볼 수 있었따.

 

이것을 사용하는 이유는 예를 들어 a라는 원본 배열이 수정되는 로직이 있는데 근데 이 다음에 원본 배열이 수정되지 않은 상태값을 기반으로 또 어떠한 로직이 필요할 때가 있는데 뭐 여러가지 이유가있겠지만 이럴때 memcpy를 주로 쓴다.

 

#incldue <iostream>
#include <string>

using namespace std;

int a[5], temp[5];

int main()
{
    for (int i = 0; i < 5; ++i)
        a[i] = i;
    
    memcpy(temp, a, sizeof(a));
    
    for (int i : temp)
        cout << i << ' ';
    
    cout << '\n';
    
    // 원본 배열 a를 수정
    a[4] = 1000;
    
    for (int i : a)
        cout << i << ' ';
    
    cout << '\n';
    
    // 다시 원래 배열을 가지고 있는 temp로 다시 카피
    memcpy(a, temp, sizeof(temp));
    
    for (int i : a)
        cout << i << ' ';
    cout << '\n';
    
    return 0;
}

 

하지만 여기서 주의해야 할 점은 vector는 깊은 복사가 되지 않음..ㅇㅇ

 

한 번 확인해보자.

 

나는 내가 본것만 믿어요

 

 

#include <iostream>
#include <string>

using namespace std;

int main()
{
    vector<int> v {1, 2, 3};
    vector<int> ret(3);
    memcpy(&ret, &v, 3*sizeof(int));
    
    cout << ret[1] << '\n';
    ret[1] = 100;
    cout << ret[1] << '\n';
    cout << v[1] << '\n';
    
    return 0;
}

 

 

음 원본도 값이 바뀐 것을 확인할 수 있다.

이를 Trivially Copyable라고 한다.

 

사소하게 카피할 수 있는거?

말그대로 그거다 단순복사가 가능한 애들만 memcpy를 사용할 수 있다.

 

memcpy()의 Trivially Copyable

src가 가리키는 객체로부터 dest가 가리키는 객체로 바이트 단위로 count만큼 복사한다.

만약 객체들이 겹치거나 단순 복사가 가능하지 않은 경우 (이를 Trivially Copyable이라고 함.)
해당 함수는 올바르게 동작하지 않을 수 있다.

라고 한다.

 

그냥 간단하게 '안돼'라고 생각하자

 

ㅠㅠ

안돼...

 

이를 확인할 수 있는 방법은 is_trivial를 통해 해당 타입이 TriviallyCopyable한지 확인할 수 있다.

vector는 그렇지 않는 것을 볼 수 있다.

 

#include <iostream>

using namespace std;

int main()
{
    if (is_trivial<vector<int>>())
        cout << "Hello Santos!\n";
}

 

memcpy는 Array에서만 동작!!!!!!!

 

 

그리고 주의할점

memcpy()을 쓸 때 복사하는 배열(src)과 복사되는 대상(dest)의 배열의 메모리가 겹치면 UB가 발생할 수 있다.

예를 들어 다음과 같이 배열 a의 일부분을 다시 배열 a에 복사하려고 한다면 UB가 발생할 수 있다.

Undefined Behavior 예측할 수 없는 오류라는 것이다.

복사하는 배열대상의 메모리 주소는 겹치지 않도록 주의하자!!

 

int a[8];
memcpy(&a[1], a, sizeof(int) * 7);

 

이런거 조심

 

'C++ 나만의 복습' 카테고리의 다른 글

sort()  (0) 2024.04.07
copy()  (0) 2024.04.07
쓰지 말아야 할 초기화 방법 {0, }  (0) 2024.04.07
memset()  (0) 2024.04.07
fill()  (0) 2024.04.07