C++ 복사생성자

#include <iostream>
using namespace std;

class SoSimple
{
private:
    int num;
public:
    SoSimple(int n) : num(n)
    {
        cout << "New Object : " << this << endl;
    }
    SoSimple(const SoSimple& copy) :num(copy.num)
    {
        cout << "New Copy obj: " << this << endl;
    }
    ~SoSimple()
    {
        cout << "Destory obj: " << this << endl;
    }
};

SoSimple SimpleFuncObj(SoSimple ob)
{
    cout << "Parm ADR: " << &ob << endl;
    return ob;
}

int main(void)
{
    SoSimple obj(7);
    SimpleFuncObj(obj);

    cout << endl;

    SoSimple tempRef = SimpleFuncObj(obj);
    cout << "Return Obj " << &tempRef << endl;

    return 0;
}

tempRef에 대해 복사생성자가 호출 안되는 이유는 알고 있는데, 그것 말고 tempRef에 대해서는 소멸자가 호출이 안되는 이유가 복사생성자가 호출안되는 이유와 같고 따라서 임시객체에 대해 소멸자가 호출되면 tempRef도 소멸자가 호출된거와 같은거니깐 그런건가요 ?

2답변

  • New Object : 0x7ffeab864678
    New Copy obj: 0x7ffeab864668
    Parm ADR: 0x7ffeab864668
    New Copy obj: 0x7ffeab864670
    Destory obj: 0x7ffeab864670
    Destory obj: 0x7ffeab864668
    
    New Copy obj: 0x7ffeab864650
    Parm ADR: 0x7ffeab864650
    New Copy obj: 0x7ffeab864658
    Destory obj: 0x7ffeab864650
    Return Obj 0x7ffeab864658
    Destory obj: 0x7ffeab864658
    Destory obj: 0x7ffeab864678
    

    다음과 같은 실행 결과에서 Destory obj: 0x7ffeab864658tempRef에 대한 소멸자 호출 결과입니다.

    복사 생략에 의해서 SimpleFuncObj(obj)의 반환 객체가 바로 tempRef가 됩니다.

    SimpleFuncObj()는 값복사를 통한 반환을 하기 때문에 return시 복사 생성자가 호출되지만 그 때 생성되는 임시 객체를 tempRef에 또다시 복사할 필요가 없이 tempRef라고 칭하게 되면 복사 과정이 한 단계 생략할 수 있습니다.

    C++ 컴파일러는 이러한 점을 잘 알고 있고 최대한 쓸때 없는 과정을 배제하기 위해서 복사 생략을 하게 됩니다.

    좀더 정확히는 임시 객체 자체를 생성하지 않고 바로 tempRef 변수가 생성한 것으로 이해하시면 됩니다.


    좀더 자세히 설명하겠습니다.

    SoSimple tempRef = SimpleFuncObj(obj); 에서 함수의 반환 객체는 이름이 없기 때문에 통상 임시 객체(좀더 정확히는 rvalue)라고 부릅니다. 이 임시 객체는 tempRef에 대입 혹은 복사 생성자의 인자로 전달되게 되는데 C++에서는 복사가 생략 되기 때문에 대입 혹은 복사 생성자가 호출 되지 않고 이 임시객체에 tempRef라는 이름을 부여하게 됩니다. 객체가 이름이 부여되었기 때문에 해당 이름이 유효한 생명주기 내에서 객체는 존재하게 됩니다. 이름이 부여 되지 않은 객체는 표현식이 끝나면 제거되게 되지만 이 상황에서는 tempRef라는 이름이 부여되어으므로 main이 끝나기 전까지 살아 남게 됩니다.

    즉, tempRef가 함수 호출 결과로 반환된 임시 객체라고 보시면 됩니다.

    • 네, 복사과정이 한 단계 생략되는건 알게 되었습니다. 다만, 열혈 C++에서는 tempRef의 소멸자가 아니라 임시객체에 대한 소멸자가 호출된거라고 하던데 결국은 똑같은 말인거죠 ? 원종운 2018.11.8 00:12
    • 아니요. 다릅니다. tempRef의 소멸자가 호출 된 것이며 SoSimple tempRef = SimpleFuncObj(obj); 에서 임시 객체는 생성되지 않습니다.다만 main두번째 줄 SimpleFuncObj(obj); 에서는 임시객체가 생성되어 바로 소멸합니다. 유동욱 2018.11.8 00:19
    • 덧글에는 사진이 안되어 답변에 사진을 올렸습니다. 한번 설명을 봐주실 수 있나여 ? 결과의 밑에서2번째요 ! 원종운 2018.11.8 00:22
    • 책에서 서술한 이야기는 틀리지 않습니다. 책에서 임시객체가 tempRef란 이름으로 할당되었다고 하였는데 이렇게 이름이 붙는 순간 더이상 임시 객체라 부르지 않습니다. tempRef는 함수 호출이 끝나기 전까지 존재하지 않다 객체기 반환되면 거기에 이름이 붙게 되는 식이라고 생각 하시면 됩니다. 유동욱 2018.11.8 00:27
    • 아, 그러면 정리를 하게되면 복사생략이되어서 임시객체가 tempRef에 복사되지 않고 바로 임시객체가 tempRef라는 명칭으로 불리게 되고, 그렇게 불리게 되는 이상, 임시객체의 의미,존재가 사라진다라는거죠 ? 원종운 2018.11.8 00:29
    • 아니요. 임시 객체에 tempRef란 이름이 붙는다고 생각하시면 됩니다. 존재가 사라지는게 아니에요. 유동욱 2018.11.8 00:34
    • 임시객체가 tempRef가 되고, tempRef 소멸자가 호출되면서 tempRef가 가르키는 임시객체가 소멸되는거구요 ? 원종운 2018.11.8 00:38
    • 내용 추가하였습니다. 유동욱 2018.11.8 01:03

ᕕ( ᐛ )ᕗ
로그인이 필요합니다

작성한 답변에 다른 개발자들이 댓글을 작성하거나 댓글에 좋아요/싫어요를 할 수 있기 때문에 계정을 필요로 합니다.