C++) 임시 객체 리턴 개선

Wonjun Lee·2026년 7월 26일

문제 상황

Animal create_new_anial() {
    std::cout << CREATE_ANIMAL_MSG << std::endl;
    Animal new_animal;

    std::string temp_name;

    while (true) {
        std::cout << "Name of new animal (1~30 chars): ";
        std::getline(std::cin >> std::ws, temp_name);
        if (temp_name.length() >= 1 &&
            temp_name.length() <= 30) {
            std::strncpy(new_animal.name, temp_name.c_str(), sizeof(new_animal.name) - 1);
            new_animal.name[sizeof(new_animal.name) - 1] = '\0';
            break;
        }
        std::cout << "Name must be between 1 and 30 characters.\n";
    }

    std::cout << "how old is you animal : ";
    std::cin >> new_animal.age;

    new_animal.food = DEFAULT_FOOD;
    new_animal.clean = DEFAULT_CLEAN;
    new_animal.health = DEFAULT_HEALTH;

    return new_animal;
}
list[animal_count++] = &create_new_anial();

create_new_animal 함수가 지역 스코프에서 구조체 new_animal을 생성한다. 이를 리턴하였고 이것을 list배열이 받아 참조한다.

발생 가능한 문제

내가 생각하기로 Animal 타입으로 레퍼런스가 아닌 인스턴스를 그대로 리턴하면 복사가 수행되어 안전할 것이라고 판단했다.

Aniaml animal = create_new_animal();

이렇게 처리한다면 안전하지만 앞에 &를 붙이면 cpp 표준에서 적용 불가하다고 한다.
함수 반환값은 임시 객체인 prvalue이며, 컴파일러가 다음과 같은 오류를 낼 수 있다.

error: taking the address of a temporary object

임시 객체는 위 반환되는 라인 이후로 파괴되고 list의 포인터는 dangling pointer가 된다.

이로인해 발생 가능한 문제는 다음과 같다.

  • 이상한 값 출력
  • 이전에는 동작하다가 갑자기 오류 발생
  • 메모리 훼손
  • 프로그램 크래시
  • 디버그 빌드에서는 실패하지만 릴리스 빌드에서는 우연히 동작

Cpp에서 값의 종류
1. lvalue = 이름이 있는 객체, 주소를 가질 수 있다.
2. xvalue = 곧 소멸될 객체, 주소를 가질 수 있다. (실제 객체이지만 이동(move) 대상이 되는 객체.)
3. prvalue = 순수한 값(pure rvalue), 주소를 가질 수 없다. (계산 결과나 함수 반환 같은 순수한 값)

10;
&10; // 불가. 이런게 prvalue

move는 std::move() 함수 호출로 이 객체를 더이상 사용하지 않으니 컴파일러에게 회수하라고 알려주는 역할 이동 생성자가 호출되고, 메모리 복사 없이 포인터를 넘겨줌.

std::string s1 = "Hello";
std::string s2 = std::move(s1);

std::cout << s1;

마지막줄 s1은 어떤 값인지 보장되지 않음.
결국 대입할 때 std::move() 호출해주면 되며, 실제 이동이 발생하는지는 내부에 저장된 값에 따라 컴파일러가 판단함.

해결책

  1. list를 값 배열로 변경하기.
  • 복사 발생하여 안전하게 저장 가능하다.
  • 단점은 크기 동적 변경이 어렵고, 항상 MAX_LIST_SIZE 만큼 메모리를 점유한다.
  1. vector 사용
std::vector<Animal> list;
list.reserve(MAX_ANIMAL);  // 선택사항

list.push_back(create_new_animal());  // 내부에서 복사 저장, 안전
  • 크기 자동 관리
  • 크기를 별도 변수로 관리할 필요 없어지고 비교도 쉬워짐. list.size();
  1. new를 이용해 새로 생성
Animal * list[MAX_ANIMAL];

Animal temp = create_new_animal();
list[animal_count++] = new Animal(temp);  // 힙에 복사본 생성

프로그램 종료 전 반드시 해제 필요:
for (int i = 0; i < animal_count; i++) {
    delete list[i];
}
  • 기존 포인터 배열 유지 가능함.
  • 마지막에 반드시 delete 해야함. 안그러면 메모리 누수 발생.
profile
Samsung Electronics. SW Engineering.

0개의 댓글