ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Effective C++...10
    일지 2022. 6. 9. 08:03

    Operator=에서는 자기 대입에 대한 처리가 빠지지 않도록 하자

    자기 대입이란?

    어떤 객체가 자기 자신에 대해 대입 연산자를 적용하는 것을 말한다.


    class Widget { ... };Widget w;

    w = w;

    // 같은 변수에 대입하는 경우

    a[i] = a[j]; // 만약 i와 j가 같은 경우

    *px = *py; // 자기 대입이 될 가능성이 높음


     

    자기 대입이 문제가 되는 경우

    포인터를 사용하고 있고 대입할 때 기존 포인터 값을 삭제하고 대입하는 값을 복사해 사용하는 코드가 있을 때, 자기 대입이 발생한 경우 제거된 값을 복사하려고 시도하게 될 수 있다.


    // Widget에 Bitmap* pb가 있다.

    Widget& Widget::operator=(const Widget& rhs)

    {

        delete pb;

        pb = new Bitmap(*phs.pb); // 자기 대입인 경우 전 줄에서 pb가 삭제되었으므로 문제가 될 것이다.

     

        return *this;

    }


     

    자기 대입을 막는 방법

    이 것을 회피한 전통적인 해결 방법은 다음과 같이 첫 라인에 일치성 검사 코드를 추가하는 것이다.


    Widget& Widget::operator=(const Widget& rhs)

    {

        if (this == &rhs) return *this; // 자기 대입인 경우 그대로 반환하고 종료한다.

     

        delete pb;

        pb = new Bitmap(*phs.pb);

     

        return *this;

    }


     

    다른 방법으로는 문장을 조금 수정해서 안전하게 동작하도록 만들 수 있다.


    Widget& Widget::operator=(const Widget& rhs)

    {

        Bitmap* pOrig = pb; // 기존의 값을 임시 변수에 저장해둔다.

        pb = new Bitmap(*phs.pb); // 새로운! 값을 생성해 pb에 저장한다.

        delete pOrig; // 안전하게 기존 값을 제거한다.

     

        return *this;

    }


     

    또 다른 방법으로 복사 후 맞바꾸기라는 기법을 사용하면 도움이 된다.


    class Widget {

        void swap(Widget& rhs); // *this의 데이터와 rhs의 데이터를 맞바꾸는 함수.

    }

     

    Widget& Widget::operator=(const Widget& rhs)

    {

        Widget temp(rhs); // 임시 변수를 만들고

        swap(temp); // 데이터를 서로 바꾼 뒤 함수를 빠져나가면

        return *this; // 임시 변수가 삭제되면서 대입이 완료된다.

    }


     

    복사 후 맞바꾸기 기법은 C++의 특성을 이용해 다음과 같이 수정할 수 있다.


    Widget& Widget::operator=(Widget rhs) // 값에 의한 참조로 인해 복사되어 온다.

    {

        swap(rhs); // 값으로 참조된 인자와 데이터를 서로 바꾼다.

        return *this;

    }


     

    ※ 값에 의한 참조로 제작한 경우 명확성이 떨어질 수 있으나 변수의 복사가 생성자단에서 일어나므로 조금 더 효율적일 수 있다.

     

    댓글

Designed by Tistory.