sliver__

[Mastering C++ Programming] - auto ptr 본문

CS/C++

[Mastering C++ Programming] - auto ptr

sliver__ 2022. 12. 7. 16:40
728x90
  • auto_ptr 스마트 포인터는 raw pointer를 가져와 래핑하고 auto_ptr 개체가 범위를 벗어날 때마다 원시 포인터가 가리키는 메모리가 다시 해제되도록 합니다. 
  • 언제든지 auto_ptr 스마트 포인터 하나만 개체를 가리킬 수 있습니다. 
  • 따라서 하나의 auto_ptr 포인터가 다른 auto_ptr 포인터에 할당될 때마다 소유권은 할당을 받은 auto_ptr 인스턴스로 이전됩니다. 
  • auto_ptr 스마트 포인터가 복사될 때도 마찬가지입니다.


#include <iostream>
#include <string>
#include <memory>
#include <sstream>
using namespace std;

class MyClass {
      private:
           static int count;
           string name;
      public:
           MyClass() {
                 ostringstream stringStream(ostringstream::ate);
                 stringStream << "Object";
                 stringStream << ++count;
                 name = stringStream.str();
                 cout << "\nMyClass Default constructor - " << name << endl;
           }
           ~MyClass() {
                 cout << "\nMyClass destructor - " << name << endl;
           }

           MyClass ( const MyClass &objectBeingCopied ) {
                 cout << "\nMyClass copy constructor" << endl;
           }

           MyClass& operator = ( const MyClass &objectBeingAssigned ) {
                 cout << "\nMyClass assignment operator" << endl;
           }

           void sayHello( ) {
                cout << "Hello from MyClass " << name << endl;
           }
};

int MyClass::count = 0;

int main ( ) {

   auto_ptr<MyClass> ptr1( new MyClass() );
   auto_ptr<MyClass> ptr2( new MyClass() );

   return 0;

}

 

  • 결과는 아래와 같다.
g++ main.cpp -std=c++17

main.cpp: In function ‘int main()’:
main.cpp:40:2: warning: ‘template<class> class std::auto_ptr’ is deprecated [-Wdeprecated-declarations]
 auto_ptr<MyClass> ptr1( new MyClass() );
 
In file included from /usr/include/c++/6/memory:81:0,
 from main.cpp:3:
/usr/include/c++/6/bits/unique_ptr.h:49:28: note: declared here
 template<typename> class auto_ptr;
 
main.cpp:41:2: warning: ‘template<class> class std::auto_ptr’ is deprecated [-Wdeprecated-declarations]
 auto_ptr<MyClass> ptr2( new MyClass() );
 
In file included from /usr/include/c++/6/memory:81:0,
 from main.cpp:3:
/usr/include/c++/6/bits/unique_ptr.h:49:28: note: declared here
 template<typename> class auto_ptr;
 
 
 g++ main.cpp -Wno-deprecated

./a.out

MyClass Default constructor - Object1

MyClass Default constructor - Object2

MyClass destructor - Object2

MyClass destructor - Object1

 

  • 하지만 auto_ptr은 소유권 이전 문제로 사용하지 않는다.
  • 예제는 아래와 같다.
int main ( ) {

    auto_ptr<MyClass> ptr1( new MyClass() );
    auto_ptr<MyClass> ptr2( new MyClass() );

    ptr1->sayHello();
    ptr2->sayHello();

    //At this point the below stuffs happen
    //1. ptr2 smart pointer has given up ownership of MyClass Object 2
    //2. MyClass Object 2 will be destructed as ptr2 has given up its 
    //   ownership on Object 2
    //3. Ownership of Object 1 will be transferred to ptr2
    ptr2 = ptr1;

    //The line below if uncommented will result in core dump as ptr1 
    //has given up its ownership on Object 1 and the ownership of 
    //Object 1 is transferred to ptr2.
    // ptr1->sayHello();

    ptr2->sayHello();
   
    return 0;

}
  • auto_ptr ptr1 개체가 포인터라고 믿게 만들지만 실제로 ptr1 및 ptr2는 로컬 변수로 스택에 생성된 auto_ptr 개체일 뿐입니다. 
  • auto_ptr 클래스는 -> 포인터 연산자와 * 역참조 연산자를 오버로드했기 때문에 포인터처럼 보입니다. 
  • 사실, MyClass에 의해 노출된 모든 메서드는 -> 포인터 연산자를 통해서만 액세스할 수 있는 반면, 모든 auto_ptr 메서드는 스택 개체에 정기적으로 액세스하는 것처럼 액세스할 수 있습니다.

ptr2 = ptr1;
  • 앞의 코드는 단순한 대입문인 것처럼 보이지만 auto_ptr 내에서 많은 활동을 트리거합니다. 
  • 앞의 할당문으로 인해 다음 활동이 발생합니다.

    • ptr2 스마트 포인터는 MyClass 개체 2의 소유권을 포기합니다.
    • MyClass 객체 2는 ptr2가 객체 2의 소유권을 포기했기 때문에 소멸됩니다.
    • 객체 1의 소유권은 ptr2로 이전됩니다.
    • 이 시점에서 ptr1은 객체 1을 가리키지 않으며 객체 1이 사용하는 메모리를 관리할 책임도 없습니다.

 

// ptr1->sayHello();
  • ptr1 스마트 포인터가 객체 1의 소유권을 해제했기 때문에 sayHello() 메서드에 액세스를 시도하는 것은 불가능하다.
  • 이는 실제로 ptr1이 더 이상 객체 1을 가리키지 않고 객체 1을 ptr2가 소유하기 때문입니다. 
  • ptr2가 범위를 벗어날 때 객체 1에서 사용하는 메모리를 해제하는 것은 ptr2 스마트 포인터의 책임입니다. 
  • 이전 코드의 주석을 제거하면 코어 덤프가 발생합니다.

ptr2->sayHello();
return 0;

 

  • 방금 본 return 문은 main() 함수에서 스택 rewinding 프로세스를 시작합니다. 
  • 이렇게 하면 결국 ptr2의 소멸자가 호출되고 객체 1이 사용하는 메모리가 할당 해제됩니다. 
  • 모든 것이 자동으로 발생한다는 것입니다. 
  • auto_ptr 스마트 포인터는 당면한 문제에 집중하는 동안 보이지 않는 곳에서 열심히 작동합니다.

  • 그러나 다음과 같은 이유로 인해 auto_ptr은 C++11부터 더 이상 사용되지 않습니다.
    • auto_ptr 개체는 STL 컨테이너에 저장할 수 없습니다.
    • auto_ptr 복사 생성자는 원래 소스, 즉 auto_ptr에서 소유권을 제거합니다.
    • auto_ptr 복사 할당 연산자는 원래 소스인 auto_ptr에서 소유권을 제거합니다.
    • auto_ptr 복사 생성자 및 할당 연산자가 오른쪽 개체에서 소스 개체의 소유권을 제거하고 소유권을 왼쪽 개체에 할당하므로 복사 생성자 및 할당 연산자의 원래 의도는 auto_ptr에 의해 위반됩니다.
728x90
Comments