C++ 복사생성사의 호출

조회수 2159회
#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;
}

SoSimple tempRef = SimpleFuncObj(obj);

여기서 tempRef로 SimpleFuncObj(obj)이 복사생성 될줄 알았는데 안그러더라구요.
이리저리 검색해본결과 컴파일러가 효율을 위해 따로 tempRef를 생성하지않는다라고
나와있던데 원래 그런건가요 ?

1 답변

  • 어떤 값을 복사 안한다는 의미인지요?

    실행결과를 보면 복사생성자가 호출되는 것으로 보입니다. (다음은 g++ 컴파일러를 사용한 경우입니다.)

    New Object : 0x7ffffb3509f0      <-- SoSimple obj(7)
    New Copy obj: 0x7ffffb350a10     <-- SimpleFuncObj의 obj  인자를 복사하기 위한 복사생성자 호출 );
    Parm ADR: 0x7ffffb350a10
    New Copy obj: 0x7ffffb350a00     <-- SimpleFuncObj의 return을 위한 복사생성자
    Destory obj: 0x7ffffb350a00      <-- SimpleFuncObj 결과를 assign 하지 않음으로 인해 파괴 
    Destory obj: 0x7ffffb350a10      <-- SimpleFuncObj의 obj 인자의 파괴
    
    New Copy obj: 0x7ffffb350a20    <-- 두번째 SimpleFuncObj의 obj 인자를 복사하기 위한 복사 생성자 호출
    Parm ADR: 0x7ffffb350a20    
    New Copy obj: 0x7ffffb3509e0    <-- 두번째 SimpleFuncObj의 return을 위한 복사생성자
    Destory obj: 0x7ffffb350a20     <-- 두번째 SimpleFuncObj의 obj 인자의 파괴
    Return Obj 0x7ffffb3509e0
    Destory obj: 0x7ffffb3509e0     <-- 두번째 SimpleFuncObj의 결과값을 받은 tempRef 파괴
    Destory obj: 0x7ffffb3509f0     <-- 최초 obj(7)의 파괴
    

    수정답변 질문의 요지는 다음과 같은것 같네요.

    SoSimple copied = original;
    

    위와 같을 때, copied를 생성하기 위해서 복사생성자를 호출합니다.

    SoSimple copied = SimpleFuncObj(obj);
    

    그럼 위와 같은 경우에도 "SimpleFuncObj(obj)의 반환된 결과를 copied로 복사하기 위해서 복사생성자를 호출해야 하는 것 아니냐? 그런데 왜 return할 때만 복사생성자를 생성하고, return한 것을 copied에 복사하기 위한 복사생성자를 호출하지 않느냐?" 라는 질문 인것 같네요.

    이는 컴파일러의 최적화 문제를 떠나서, 여러가지 복합적인 설명이 가능합니다만, 책에서 읽은 것처럼 설명할 수도 있고, 다른 방식으로 간단히 설명하면,

    SimpleFuncObj(...)에서 반환할 때, 복사된 객체는 임시 상태로 존재합니다. 반환하는 순간에는 아직 이 객체를 누가 가리킬지 결정이 되지 않았기 때문입니다. 그런데 이 임시 객체를 copied에 assign하려고 합니다. 말그대로 이 임시 객체는 아무도 참조하지 않고 있어서, 바로 소멸될 예정입니다. 이러한 임시 객체를 굳이 복사할 필요가 있을까요? 앞의 assign(=)에 따르면 소멸할 객체를 복사할 겁니다. 하지만 어차피 참조하는 곳이 없어서 없어질 객체를 복사하는 행위보다는, 임시 객체를 assign(=) 좌측에 있는 이름으로 부르게 하는 게 더 좋지 않을까요? (assign을 통하지 않고, 임시객체가 다른 곳에서 활용될 가능성이 전혀 없기에 가능합니다. 만약 return하는 데, 동시에 여러군데 assign이 가능하다면, 질문자의 생각처럼 복사생성자를 호출하는 것이 맞을 겁니다.)

    메커니즘적으로는 실행스택(execution stack)과 관련있습니다. 이에 대한 설명은 운영체제 혹은 컴파일러 이론에서 다루고 있습니다. 실행 스택과 관련된 운용방법과 연관지어 생각해보면 쉽게 이해가 될 것입니다만, 현재로썬 앞의 문단 정도로 이해하시면 됩니다.

    • 질문을 잘못적어서 수정했습니다. ! SoSimple 객체인 tempRef가 생성될줄 알았는데 생성이 안됬다는 뜻이예요.(책에선 객체 하나의 생성을 줄여 효율을 높힌다 라고 적혀있구요) 알 수 없는 사용자 2016.5.17 23:03
    • tempRef 객체가 SimpleFuncObj(obj)에서 리턴된 객체로 복사생성될줄알았어요. 따라서 복사생성자가 Return obj : ~~ 전에 호출될꺼라고 생각했구요. 제가 궁금해 하는걸 재대로 전달하지 못한것같아요 ㅠㅠ 머라고 말해야할지.. 알 수 없는 사용자 2016.5.17 23:04
    • 여기를 처음 써봐서 그러는데 여러줄 나눠서 못적나요 ? 엔터를 누르니 덧글이 바로써지네요 알 수 없는 사용자 2016.5.17 23:06
    • 복사생성이라는 말이 참조가 복사되는 것을 말하는 것인자, 복사생성자를 호출하는 것을 애매합니다. 문맥상으로는 생성자를 호출하지 않고 복사하는 것을 원하는 것 같은데, 어떤의미인가요? 복사생성자는 새로운 객체를 만드는 것으로, 레퍼런스 타입을 쓰지 않는 한, 함수인자, return 을 통해서 전달할 때, 항상 복사하기 위해서 복사생성자를 호출합니다. 허대영(소프트웨어융합대학) 2016.5.18 00:00
    • 질문의 요지가 잘 전달되지 않아 죄송합니다 ㅠㅠ 일단 SoSimple tempRef = SimpleFuncObj(obj); 이 코드로 인해 SimpleFuncObj가 호출이 되고 SoSimple형의 객체가 리턴되고 그걸로 tempRef를 초기화하게 됩니다. 여기서 왜 tempRef가 왜 복사생성자를 호출하지 않는지가 궁금합니다. 책에서는 객체를 하나더 만들는것을 줄여 효율을 높인다라고 적혀있는데 컴파일러가 그렇게 최적화를 하는건가요 ? 제 생각대로라면 Return obj: 결과 위에 New Copy obj : tempRef가 SimpleFuncObj(obj)의 리턴값으로 복사생성이 되어야된다고 생각을 합니다. 알 수 없는 사용자 2016.5.18 00:13
    • 수정답변을 달았습니다. 제가 제대로 이해한것이 맞는지 모르겠네요? 허대영(소프트웨어융합대학) 2016.5.18 01:13
    • 완전 감사합니다 ㅠㅠ 이해했어요 책에는 그냥 효율성의 문제로 설명만 해줘서요 맞는말이긴한데 복사생성자의 개념과 직접적으로 연관이 안되서 잘 안받아들여졌거든요 알 수 없는 사용자 2016.5.18 01:35

답변을 하려면 로그인이 필요합니다.

프로그래머스 커뮤니티는 개발자들을 위한 Q&A 서비스입니다. 로그인해야 답변을 작성하실 수 있습니다.

(ಠ_ಠ)
(ಠ‿ಠ)