web-dev-qa-db-ja.com

auto_ptrが廃止されるのはなぜですか?

auto_ptrはC++ 11で非推奨になっていると聞きました。この理由は何ですか?

また、auto_ptrshared_ptrの違いを知りたいです。

84
brett

auto_ptr (とにかく最も近いもの)は unique_ptr 。 「問題」に関する限り、それは非常に単純です:auto_ptr割り当てられたときに所有権を譲渡します。 unique_ptrも所有権を移転しますが、移動セマンティクスの成文化と右辺値参照の魔法のおかげで、かなり自然にそうすることができます。また、標準ライブラリの残りの部分にもかなり「適合」します(ただし、公平性の点では、ライブラリの残りの部分が常にコピーを必要とするのではなく、移動セマンティクスに対応するように変更されたためです)。

名前の変更も歓迎(IMO)です-auto_ptrは、何を自動化しようとしているかについてはあまり説明しませんが、unique_ptrは、提供されるもののかなり合理的な(簡潔な場合)説明です。

86
Jerry Coffin

私は既存の答えは素晴らしいと思いましたが、ポインターのPoVから。 IMO、理想的な答えは、ユーザー/プログラマーの視点からの答えを持つべきです。

最初に最初に(ジェリー・コフィンが答えで指摘したように)

  • auto_ptrは状況に応じてshared_ptrまたはunique_ptrに置き換えることができます

shared_ptr:リソース/メモリの解放が心配で、オブジェクトをAT-DIFFERENT回使用できる関数が複数ある場合は、 shared_ptrを使用します。

DIFFERENT-Timesによって、object-ptrが複数のデータ構造に格納され、後でアクセスされる状況を考えてください。もちろん、複数のスレッドも別の例です。

unique_ptr:必要なのがメモリの解放のみで、オブジェクトへのアクセスがSEQUENTIALの場合、unique_ptrに進みます。

SEQUENTIALとは、どの時点でもオブジェクトが1つのコンテキストからアクセスされることを意味します。例えば。作成され、作成者が作成した直後に使用されるオブジェクト。作成後、オブジェクトは[〜#〜] first [〜#〜]データ構造に保存されます。次に、1つのデータ構造の後にオブジェクトが破棄されるか、[〜#〜] second [〜#〜]データ構造に移動されます。

この行から、shared/unique _ptrをスマートポインターと呼びます。 (auto_ptrはスマートポインターでもありますが、その設計上の欠陥のために廃止され、次の行で指摘するように、スマートポインターでグループ化しないでください。)

Auto_ptrが非推奨になり、スマートポインターが採用された理由に関する最も重要な理由は、assignment-semanticsでした。 auto_ptrを廃止する代わりに、移動セマンティクスのすべての新しい利点を追加しました。割り当てセマンティクスは最も嫌われている機能であるため、彼らはその機能を廃止することを望んでいましたが、そのセマンティクスを使用するコードが書かれているため(標準委員会は変更できません)、代わりにauto_ptrを手放す必要がありましたそれを修正します。

リンクから: http://www.cplusplus.com/reference/memory/unique_ptr/operator=/

unqiue_ptrがサポートする割り当ての種類

  • 移動の割り当て(1)
  • nULLポインターを割り当てます(2)
  • 型キャスト割り当て(3)
  • コピーの割り当て(削除済み!)(4)

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

auto_ptrでサポートされる割り当ての種類

  • コピー割り当て(4)culprit

コピーの割り当て自体が非常に嫌われた理由に来て、私はこの理論を持っています:

  1. すべてのプログラマーが本や標準を読むわけではありません
  2. auto_ptrは一見、オブジェクトの所有権を約束します
  3. すべてのプログラマーによって読み取られるわけではない、auto_ptrのlittle- *(pun意図)節は、1つのauto_ptrを別のauto_ptrに割り当て、所有権を転送します。
  4. 調査によると、この動作はすべての使用の3.1415926535%を対象としており、他のケースでは意図されていません。

意図しない動作は本当に嫌われているため、auto_ptrが嫌いです。

(C++ 11の所有権を意図的に移したいプログラマーの3.1415926536%は、std :: move()を提供しました。これにより、コードを読んで保守しようとするすべてのインターンにとって、意図が明確になりました。)

34
Ajeet Ganga

shared_ptrはコンテナ内に保存できます。 auto_ptrできません。

ところでunique_ptrは本当に直接auto_ptr置換、両方のstd::auto_ptrおよびboost::scoped_ptr

21
Ben Voigt

違いを説明するさらに別の見解....

機能的には、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*apの所有権を静かに「盗み」、apnullptrに設定したままにします。問題は、プログラマーがいなくても簡単に発生する可能性があることです。その安全性を考えました。

たとえば、class/structstd::auto_ptrメンバーがある場合、インスタンスのコピーを作成すると、コピーされるインスタンスからのポインターがreleaseになります。通常、何かをコピーしても変更されないため、奇妙で危険なほど混乱したセマンティクス。クラス/構造体の作成者は、不変条件と状態について推論するときにポインターのリリースを見落とすのは簡単です。その結果、nullのときに誤ってスマートポインターを逆参照しようとするか、または指示されたデータへのアクセス/所有権がまだ期待されていません。

11
Tony Delroy

auto_ptrは、コンテナーの要件を満たさないコピーコンストラクターを持っているため、STLコンテナーでは使用できません CopyConstructible 。 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
3
edW