C++ 임시객체와 생성자, 소멸자 호출타이밍 질문드립니다..

조회수 1808회
class Stock
{
private:
    string company;
    long shares;
    double share_val;
    double total_val;
    void set_tot()
    {
        total_val = shares * share_val;
    }
public:
    //두개의 생성자
    Stock(); //디폴트 생성자
    Stock(const string &co, long n=0, double pr=0.0);
    ~Stock(); //파괴자
    void acquire(const string &co, long n, double pr);
    void buy(long num, double price);
    void sell(long num, double prive);
    void update(double price);
    void show() const;
    const Stock& topval(const Stock &s) const;
    int Setshares() const { return shares; }
    double Setshareval() { return share_val; }
    double Settotalval() { return total_val; }
    string Setcompany() { return company; }
};

int main()
{
    {
        cout<<"생성자를 사용하여 새로운 객체 생성.\n";
        Stock stock1("NanoSmart",12,20.0);
        stock1.show();
        Stock stock2 = Stock("Boffo Objects",2,2.0);
        stock2.show();

        cout<<"stock1을 stock2에 대입한다.\n";
        stock2=stock1;
        cout<<"stock1과 stock2를 출력한다.\n";
        stock1.show();
        stock2.show();

        cout<<"생성자를 사용하여 객체를 재설정한다.\n";
        stock1 = Stock("Nifty Foods",10,50.0); //임시객체
        cout<<"갱신된 stock1: \n";
        stock1.show();
        cout<<"프로그램을 종료합니다.\n";
    }
    return 0;
}

이미지

안녕하세요? 공부를하다 이해가 잘가지 않는 부분이 있어 질문드리려고합니다. 한 예제의 생성자,소멸자,임시객체 생성,소멸에 관한 내용인데 출력결과에서 좀 혼돈이 오네요. 책에서 소스 분석에 관해 설명을 하는데요. main함수의 다음 구문을

 Stock stock2 = Stock("Boffo Objects",2,2.0); //명시적으로 생성자호출?

표준 c++는 이 구문을 컴파일러가 두가지 방법으로 실행시키는 것을 허용한다고합니다. 첫번째 방법은, Stock stock1("NanoSmart",12,20.0); 과 완전히 동일하게 실행시키는 것.(생성자를 호출하면서 바로 값을 복사하는 것 같습니다 틀렸다면 수정좀 부탁드립니다.)

다른 한가지 방법은 생성자에 대한 호출이 임시객체를 먼저 생성하고,
그 임시객체가 stock2에 복사 되는것 입니다. 그리고 나서 임시객체는 버립니다. 만약 컴파일러가 이 방법을 사용한다면 그 임시객체에 대한 파괴자가 호출 될 것입니다.

임시객체는 상수처럼 다음행으로 넘어가면 소멸된다고 배웠습니다. 그러나 임시객체를 즉각 폐기처분하기도 하지만 어떤 컴파일러는 이보다 오랫동안 임시객체를 유지하기도 하며 이러한 경우에는 소멸자 출력메시지가 더 나중에 출력될 거라고 합니다. 출력 사진을 보시면 stock2을 생성하고 소멸자 호출에 관한 출력 흔적이 없으므로 제 컴파일러에 관해 저는 두가지를 추측했습니다.

  1. Stock stock1("NanoSmart",12,20.0); 과같이 생성자를 호출하면서 값을 바로 복사하는 방식을 사용하는 것.- >이 경우라면 임시객체를 만들지 않으므로 소멸시킬일도 없기때문
  2. 1번이 아니라면 임시객체를 이용해 값을 복사하되, 임시객체는 즉각 소멸되지않고 나중에 소멸된다. ->이 경우라면 임시객체가 좀 도 오래 유지되기때문에.

그런데 이후부터 문제가 생깁니다.

stock1 = Stock("Nifty Foods",10,50.0); //임시객체

구문에서 stock1은 앞서 설명한 stock2를 초기화하는 방법과 같은 방식으로 생성자를 호출합니다. 차이점은 stock2는 초기화이고 stock1은 새로운 객체로의 대입의 차이 정도 인것 같습니다.

그런데 출력사진을 보시면 이 구문 뒤에는 안녕, Nifty Foods!라는 소멸자 호출이 이루어 졌음을 확인 할 수 있습니다. 생성자가 호출되었다는 출력 다음에 바로 소멸출력이 이루어진 것을 보아 이 경우에는 임시객체가 생성되고 다음 행으로 넘어감과 동시에 소멸되면서 소멸자가 호출 된 것을 알 수있습니다. 2번의 경우라고 볼 수있습니다

그런데 사진출력에서도 알 수 있다시피 Stock stock2 = Stock("Boffo Objects",2,2.0);에서는 즉각적으로 소멸자 호출이 이루어 지지 않았습니다.더 정확하게는 Stock("Boffo Objects",2,2.0);에 대한 소멸자 호출이 전혀 없습니다

그렇다면 이 경우에서는 Stock("Boffo Objects",2,2.0);의 소멸자 호출도 보이지 않으니 임시객체가 생성되지 않는 1번의 경우라고 생각 할 수있습니다.

의문인 것은 같은 방식임에도 불구하고 왜 이런일이 발생하는지 모르겠습니다. 제 실력에서 알 수있는 것이라고는 두개의 차이점이 초기화대입의 차이 라는 것 밖에는 모르겠습니다.

만약 이 차이가 맞다면 초기화에서는 처음 Stock stock2 = Stock("Boffo Objects",2,2.0); 이 구문은 1번방법과 같은 초기화 방법인 Stock stock1("NanoSmart",12,20.0); 이런 방식의 초기화 방법을 사용했다고 밖에 볼 수가 없는데...어떻게 이해하는 것이 좋을까요?

1 답변

  • 좋아요

    0

    싫어요
    채택 취소하기

    시작하기 전에 초기화대입은 성질이 다르다는 것을 말씀드립니다.

    일단 아래 코드는 2가지로 해석될 여지가 있습니다.

    Stock stock2 = Stock("Boffo Objects",2,2.0);
    
    • 해석 1

      Stock stock2(Stock("Boffo Objects",2,2.0));
      
    • 해석 2

      Stock stock2("Boffo Objects",2,2.0);
      

    하지만 대부분의 컴파일러는 해석 2 와 같이 동작을 하게 됩니다. 이는 복사 생략 규칙에 의해서 컴파일러가 최적화를 거치는 결과이며, C++ 17 부터는 해석 2 와 같이 동작 하도록 표준에서 명시합니다.

    즉, 임시 객체로 변수를 초기화 할 경우 복사 생략 규칙에 의해 임시 객체가 생성되지 않고 바로 객체의 생성자가 호출되도록 동작합니다.

    그에 반해 아래 코드는 변수가 생성되는 초기화 구문이 아닌 대입 연산이 동작하는 구문입니다.

    stock1 = Stock("Nifty Foods",10,50.0);
    

    대입 연산을 위해서 임시 객체 Stock("Nifty Foods",10,50.0) 는 생성되야 하고, 대입 연산이 끝나면 소멸자가 호출되게 됩니다.

    정리하면 변수를 초기화 하는 과정에서 임시 객체는 복사 생략에 의해서 생성되지 않을 수 있으며, 대입 연산은 그렇지 않습니다.

    참고로 아래의 코드는 복사 생략에 의해서 하나의 임시 객체만 생성됩니다.

    stock1 = Stock(Stock("Nifty Foods",10,50.0));
    
    • 답변 감사드립니다 속시원하게 해결됐네요 고맙습니다! codeslave 2018.5.25 00:53

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

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

(ಠ_ಠ)
(ಠ‿ಠ)