auto_ptr이 더 이상 사용되지 않는 이유는 무엇입니까?


답변:


93

에 대한 직접 대체 auto_ptr(또는 어쨌든 가장 가까운 것)는 unique_ptr입니다. "문제"에 관한 한 매우 간단합니다. auto_ptr할당 된 소유권을 이전하는 것입니다. unique_ptr또한 소유권을 이전하지만 이동 의미론의 코드화와 rvalue 참조의 마법 덕분에 훨씬 더 자연스럽게 할 수 있습니다. 또한 표준 라이브러리의 나머지 부분과 "적합"합니다 (공평하게도 일부는 항상 복사를 요구하는 대신 이동 의미 체계를 수용하도록 라이브러리의 나머지 부분을 변경했기 때문입니다).

이름의 변경은 (IMO) 환영받는 것입니다. auto_ptr자동화하려는 시도에 대해 실제로 많이 알려주지는 않지만 unique_ptr제공되는 내용에 대한 상당히 합리적인 (간결한 경우) 설명입니다.


25
auto_ptr이름 에 대한 참고 사항 : auto는 자동 변수에서와 같이 자동을 제안하고 한 가지 작업을 나타냅니다 auto_ptr. 소멸자에서 관리되는 리소스를 파괴합니다 (범위를 벗어날 때).
Vincenzo Pii 2012

14
추가 정보 : 다음은 지원 중단에 대한 공식적인 근거입니다 auto_ptr. open-std.org/jtc1/sc22/wg21/docs/papers/2005/…
Howard Hinnant

@HowardHinnant 흥미로운 문서! std :: sort ()에 std :: unique_ptr이 필요에 따라 이동 시맨틱을 사용하도록 특수화되어 있다는 점에서 이상합니다. 왜 std :: sort ()가 std :: auto_ptr에 특화되어 문서에 언급 된 복사 문제를 해결할 수 없는지 궁금합니다. 미리 감사드립니다.
Hei

2
@Hei :에 std::sort대한 전문화가 없습니다 unique_ptr. 대신 복사하지 않도록 다시 지정되었습니다. 그래서 auto_ptr실제로 수행 현대와 함께 일을 sort. 그러나 C ++ 98 / 03 sort여기의 예 알고리즘 : 모든 일반적인 알고리즘은 해당 복사본 구문을 가정 (표준 제공 또는 사용자가 작성한)을 함께 사용하면 복사 의미 가능성이 런타임 오류가있을 것이다이 auto_ptr때문에 auto_ptr자동으로 이동복사 구문. 문제는 많은 단지보다 크다 sort.
Howard Hinnant

36

기존 답변은 훌륭했지만 포인터의 PoV에서 찾았습니다. IMO, 이상적인 답변에는 사용자 / 프로그래머의 관점 답변이 있어야합니다.

먼저 (Jerry Coffin이 답변에서 지적한대로)

  • auto_ptr은 상황에 따라 shared_ptr 또는 unique_ptr로 대체 될 수 있습니다.

shared_ptr : 리소스 / 메모리 해제에 대해 걱정하고 객체를 AT-DIFFERENT 번 사용할 수있는 함수가 두 개 이상있는 경우 shared_ptr로 이동합니다.

DIFFERENT-Times에 의해 object-ptr이 여러 데이터 구조에 저장되고 나중에 액세스되는 상황을 생각해보십시오. 물론 다중 스레드가 또 다른 예입니다.

unique_ptr : 걱정되는 것이 메모리를 해제하는 것이고 객체에 대한 액세스가 SEQUENTIAL이면 unique_ptr로 이동하십시오.

SEQUENTIAL이란 어떤 지점에서든 하나의 컨텍스트에서 개체에 액세스 할 수 있다는 것을 의미합니다. 예를 들어 생성자가 생성하고 생성 한 직후에 사용한 개체입니다. 생성 후 객체는 FIRST 데이터 구조에 저장됩니다 . 그런 다음 객체는 ONE 데이터 구조 후에 파괴되거나 SECOND 데이터 구조 로 이동됩니다 .

이 줄에서 공유 / 고유 _ptr을 스마트 포인터라고합니다. (auto_ptr도 스마트 포인터이지만 디자인의 결함으로 인해 더 이상 사용되지 않으며 다음 줄에서 지적 할 것이라고 생각하므로 스마트 포인터로 그룹화해서는 안됩니다.)

auto_ptr이 smart-pointer를 선호하는 이유에 대한 가장 중요한 이유는 할당 의미론입니다. 만약 그렇지 않다면, auto_ptr을 더 이상 사용하지 않는 대신 auto_ptr에 모든 새로운 이동 의미 체계를 추가했을 것입니다. 할당 의미론이 가장 싫어하는 기능 이었기 때문에 그들은 그 기능이 사라지기를 원했지만 그 의미를 사용하는 코드가 작성 되었기 때문에 (표준위원회는 변경할 수 없습니다), 대신 auto_ptr을 놓아야했습니다. 수정.

링크에서 : http://www.cplusplus.com/reference/memory/unique_ptr/operator=/

unqiue_ptr에서 지원하는 할당의 종류

  • 이동 할당 (1)
  • 널 포인터 할당 (2)
  • 형변환 할당 (3)
  • 복사 할당 (삭제됨!) (4)

출처 : http://www.cplusplus.com/reference/memory/auto_ptr/operator=/

auto_ptr에서 지원하는 할당의 종류

  • 복사 할당 (4) 범인

이제 복사 할당 자체가 왜 그렇게 싫어 졌는지에 대한 이유를 살펴보면 다음과 같은 이론이 있습니다.

  1. 모든 프로그래머가 책이나 표준을 읽는 것은 아닙니다.
  2. auto_ptr은 객체의 소유권을 약속합니다.
  3. 모든 프로그래머가 읽지 않는 auto_ptr의 little-* (말장난 의도) 절은 하나의 auto_ptr을 다른 것으로 할당하고 소유권을 이전합니다.
  4. 연구에 따르면이 동작은 모든 사용량의 3.1415926535 %를 대상으로하며 다른 경우에는 의도하지 않은 것으로 나타났습니다.

의도하지 않은 동작은 정말 싫어하기 때문에 auto_ptr에 대한 싫어요.

(의도적으로 소유권을 이전하려는 프로그래머의 3.1415926536 %의 경우 C ++ 11은 std :: move ()를 제공하여 코드를 읽고 유지하려는 모든 인턴에게 의도를 명확히했습니다.)


1
당신이 있기 때문에 결코 두 싶지 auto_ptr같은 객체를 가리키는 값 (그들은 소유권을 공유주지 않기 때문에를, 다이에 첫 번째 치명적인 유산으로 다른 사람을 떠나,이 또한 마찬가지입니다 unique_ptr사용), 당신이 제안 할 수 있었는지 의도 나머지 96.8584073465 %는 전체 사용량의?
Marc van Leeuwen 2014-06-19

그들 모두에 대해 말할 수는 없지만, 나는 그들이 객체 소유권이 이동 되고 있다고 생각할 것이며 단지 복제가 아니라 오류 라고 생각할 것 입니다.
Ajeet Ganga 2014

@AjeetGanga 다음 문구 '작은 * (말장난 의도)'에서 "말장난 의도"라고 언급하셨습니다. 이 구절은 저에게 새롭고 어쨌든 저는 그것을 검색했고 여기에 의도적으로 한 농담이 있다는 것을 알게되었습니다. 여기서 그 농담은 무엇입니까? 알고 싶어요.
VINOTH ENERGETIC

@AjeetGanga 당신은 '작은 * (말장난 의도), 모든 프로그래머가 읽지 않는 auto_ptr의 절과 같이 하나의 auto_ptr을 다른 것으로 할당하고 소유권을 이전합니다'라고 언급했습니다. a와 b를 정수로 두 개의 auto ptr이 있다고 가정 해 봅시다. *a=*b;여기서 b의 값만 a에 복사 되므로 할당을 수행하고 있습니다. 나는 a와 b의 소유권이 여전히 같은 사람들에게 있기를 바랍니다. 당신은 owenership이 양도 될 것이라고 언급했습니다. 어떻게 될까요?
VINOTH ENERGETIC

@VINOTHENERGETIC Ajeet는 auto_ptr객체 자체 에 할당하는 것에 대해 이야기 했습니다. 지적 가치에 대한 할당은 소유권에 영향을 미치지 않으며 소유권과 관련이 없습니다. 아직 사용하고 auto_ptr있지 않습니까?
underscore_d

23

shared_ptr용기 안에 보관할 수 있습니다. auto_ptr캔트.

BTW unique_ptr는 실제로 직접 auto_ptr대체품이며 std::auto_ptrboost::scoped_ptr.


11

차이점을 설명하는 또 다른 방법 ....

기능적으로 C ++ 11 std::unique_ptr은 "고정"입니다 std::auto_ptr. 둘 다-실행 중 어느 시점에서든-지적 대상 객체에 대해 단일 스마트 포인터 소유자가 있어야하는 경우에 적합합니다.

중요한 차이점은 =>아래 줄에 표시된 만료되지 않는 다른 스마트 포인터의 복사 구성 또는 할당에 있습니다.

   std::auto_ptr<T> ap(...);
   std::auto_ptr<T> ap2(get_ap_to_T());   // take expiring ownership
=> std::auto_ptr<T> ap3(ap);  // take un-expiring ownership ala ap3(ap.release());
   ap->xyz;  // oops... can still try to use ap, expecting it to be non-NULL

   std::unique_ptr<T> up(...);
   std::unique_ptr<T> up2(get_up_to_T());   // take expiring ownership
=> std::unique_ptr<T> up3(up);  // COMPILE ERROR: can't take un-expiring ownership
=> std::unique_ptr<T> up4(std::move(up));  // EXPLICIT code allowed
=> std::unique_ptr<T> up4(up.release());   // EXPLICIT code allowed

위에서 ap3조용히의 소유권을 "훔쳐" *apap설정 한 상태로 두면 nullptr문제는 프로그래머가 안전을 고려하지 않고 너무 쉽게 발생할 수 있다는 것입니다.

예를 들어 class/ structstd::auto_ptr멤버가있는 경우 인스턴스의 복사본을 만들면 복사되는 인스턴스 release의 포인터가됩니다. 일반적으로 무언가를 복사해도 수정되지 않으므로 이상하고 위험 할 정도로 혼란스러운 의미입니다. 클래스 / 구조체 작성자가 불변 및 상태에 대해 추론 할 때 포인터 해제를 간과하기 쉽고 결과적으로 null 일 때 스마트 포인터 역 참조를 시도하거나 여전히 지적 된 데이터에 대한 예상 액세스 / 소유권이 없습니다.


auto_ptr 조용히 소유권을 "훔칩니다"+1
camino

3

auto_ptr은 컨테이너 CopyConstructible의 요구 사항을 충족하지 않는 복사 생성자를 가지고 있으므로 STL 컨테이너에서 사용할 수 없습니다 . unique_ptr은 복사 생성자를 구현하지 않으므로 컨테이너는 대체 메서드를 사용합니다. unique_ptr은 컨테이너에서 사용할 수 있으며 shared_ptr보다 std 알고리즘에서 더 빠릅니다.

#include <iostream>
#include <type_traits>
#include <vector>
#include <memory>

using namespace std;

int main() {
  cout << boolalpha;
  cout << "is_copy_constructible:" << endl;
  cout << "auto_ptr: " << is_copy_constructible< auto_ptr<int> >::value << endl;
  cout << "unique_ptr: " << is_copy_constructible< unique_ptr<int> >::value << endl;
  cout << "shared_ptr: " << is_copy_constructible< shared_ptr<int> >::value << endl;

  vector<int> i_v;
  i_v.push_back(1);
  cout << "i_v=" << i_v[0] << endl;
  vector<int> i_v2=i_v;
  cout << "i_v2=" << i_v2[0] << endl;

  vector< unique_ptr<int> > u_v;
  u_v.push_back(unique_ptr<int>(new int(2)));
  cout << "u_v=" << *u_v[0] << endl;
  //vector< unique_ptr<int> > u_v2=u_v;  //will not compile, need is_copy_constructible == true
  vector< unique_ptr<int> > u_v2 =std::move(u_v);  // but can be moved
  cout << "u_v2=" << *u_v2[0] << " length u_v: " <<u_v.size() << endl;

  vector< shared_ptr<int> > s_v;
  shared_ptr<int> s(new int(3));
  s_v.push_back(s);
  cout << "s_v=" << *s_v[0] << endl;
  vector< shared_ptr<int> > s_v2=s_v;
  cout << "s_v2=" << *s_v2[0] << endl;

  vector< auto_ptr<int> > a_v;  //USAGE ERROR

  return 0;
}

>cxx test1.cpp -o test1
test1.cpp: In function âint main()â:
test1.cpp:33:11: warning: âauto_ptrâ is deprecated (declared at /apps/hermes/sw/gcc/gcc-4.8.5/include/c++/4.8.5/backward/auto_ptr.h:87) [-Wdeprecated-declarations]
   vector< auto_ptr<int> > a_v;  //USAGE ERROR
           ^
>./test1
is_copy_constructible:
auto_ptr: false
unique_ptr: false
shared_ptr: true
i_v=1
i_v2=1
u_v=2
s_v=3
s_v2=3
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.