3

の意味は何auto_ptrですか?このコードを見てください:

#include <iostream>
#include <memory>

class A
{
public:
    ~A()
    {
        std::cout << "DEST";
    };
};

void func(A* pa)
{
    std::cout << "A pointer";
}

void test()
{
    A a;
    std::auto_ptr<A> pA(new A);
    //func(pA);  //compiler error here cannot convert parameter 1 from 'std::auto_ptr<_Ty>' to 'A *' 
    std::cout << "end";
}

int main(int argc, char* argv[])
{
    test();
    return 0;
}

これを使う意味は何auto_ptrですか?

  • 通常のクラス初期化変数(a)として、スコープ外になるとクラスデストラクタを呼び出します。
  • このポインターをクラスポインター (func) を持つ関数に渡すことはできません
  • auto_ptr が delete not を呼び出すため、ポインターauto_ptrA[]orに使用できません。char[]delete[]

唯一の考えは、delete を書く必要がないということですが、範囲外になったときにポインターが破棄される場合、ポインターの意味は何ですか。ポインターを使用して、変数のライブを制御します。

auto_ptr通常の変数初期化はスタック上にあり、ポインターはヒープ上にありますが、通常のポインターではなく使用する意味を教えてください。

4

5 に答える 5

6

唯一の考えは、削除を書く必要がないということです

うん、これは非常に大きな利点です。メモリ リークは遭遇する最も一般的なバグの 1 つです。

スコープから出たときに破壊される場合、ポインターの意味は何ですか。ポインターを使用して、変数のライブを制御します。

その考え方からシフトし、スコープを使用して変数の寿命を定義します。これらを適切なスコープで宣言するだけで、クリーンアップについて心配する必要がなくなります。それが要点です。

あなたの例は不自然ですが、なぜそれが価値があるのか​​ はまだわかります. delete確かに、まったく何もしない 2 行の関数を呼び出すことを忘れないでしょう。実際のアプリケーションでは、事態はさらに複雑になります。

たくさんのオブジェクトがある場合new、関数が終了するとオブジェクトがクリーンアップされるという事実に頼ることができます。同じことがクラスにも当てはまります。インスタンスが範囲外になると、そのデストラクタに頼ってメモリの割り当てを解除することができます。例外がスローされたときに何が起こるかを考えてみましょう。auto_ptr がなければ、考えられるすべての例外と考えられるすべてのリターン パスを確実に処理して、後始末を確実に行う必要があります。

また...

通常の変数の初期化はスタック上にあり、ポインターはヒープ上にあります

そうではありません。この場合のポインタには自動保存期間がありますが、それが指すものはそうではありません。

を渡すとコンパイラが吠える理由auto_ptrは、関数がauto_ptr. get()ポインター自体を渡すために呼び出す必要があります。

auto_ptrとはいえ、どちらも使用すべきではありません。C++ 0x コンパイラにアクセスできる場合は、unique_ptrを使用してください。

于 2011-10-23T17:58:13.027 に答える
4

auto_ptr(または他のスマート ポインター) を使用してメモリを管理する理由はたくさんあります。そのコードを変更しましょう:

void test()
{
    A a;
    std::auto_ptr<A> pA(new A);
    if(SomeFunc())
      return;
    //func(pA);  //compiler error here cannot convert parameter 1 from 'std::auto_ptr<_Ty>' to 'A *' 
    std::cout << "end";
}

pAがスマート ポインターでない場合、メモリ リークが発生します。しかし、そうであるため、メモリが適切に解放されることがわかっています。心配する必要はありません。例外がスローされた場合SomeFuncでも、解放されます。

ポインタの受け渡しに関する問題を解決するには、次のようにします。

void test()
{
    A a;
    std::auto_ptr<A> pA(new A);
    func(pA.get());
    std::cout << "end";
}

オブジェクトはpAまだメモリを所有しています。削除してはいけませんfunc保存してはいけません。

于 2011-10-23T17:58:30.713 に答える
3

重要

std::auto_ptrこれには多くの欠点がありstd::unique_ptr、コンパイラで提供されている場合は、通常は代わりに使用する必要があることに注意してください。(そうでない場合は、コンパイラを更新してください! :))

さて、あなたの質問に戻ります...


この auto_ptr を使用する意味は何ですか? 通常のクラス初期化変数 (a) として、スコープ外に出るときにクラス デストラクタを呼び出します。

丁度。その理由auto_ptrは、厳密な所有権のセマンティクスを強制するためです。これにより、ポインター自体が破棄されたときにオブジェクトが適切に破棄されます。

このポインターをクラス ポインター (func) を持つ関数に渡すことができません

get()生ポインタを検索するために使用する必要があります。get()関数呼び出しにポインターを渡すときに使用すると、関数がオブジェクトの所有権を取得しないことを意味します (オブジェクトはauto_ptrまだ所有しており、関数が戻った後も有効であることが期待されます)。

または、 on を使用release()して未加工のポインターを取得しauto_ptr、オブジェクトの所有権がもはや責任を負わないことを示すことができます。

auto_ptr は delete[] ではなく delete を呼び出すため、A[] または char[] にポインター auto_ptr を使用することはできません。

うん、それは問題だ。が導入されauto_ptrてから使用しなくなった理由の 1 つです。unique_ptr同じことを行いますが、より安全に (= 簡単に) 使用でき、より汎用性があります。

唯一の考えは、delete を書く必要はないということですが、範囲外に出たときに破棄される場合、ポインターの意味は何ですか。

あなたがそれを忘れないように:-)または、auto_ptr(またはunique_ptrクラスオブジェクトのメンバーとしてより良い)を使用できます。

しかし、通常のポインターではなく auto_ptr を使用する意味を教えてください。

簡単に言えば、多くのポインターが単一のオブジェクトを指すことができます。あらゆる種類のスマート ポインターが存在し、どのポインターがオブジェクトを所有するか (= オブジェクトを解放する責任があるか) を記帳するために型システムを使用します。


補足

別のオブジェクトのインスタンスを所有する (可能性がある) クラスがある場合は、単純に次のように記述します。

class X {
    // ...
    X() : ptr(new Type()) {}
    X(Type ptr) : ptr(ptr) {}
    // ...
    void setPtr(Type ptr2) { ptr.reset(ptr); }
    // ...
    std::unique_ptr<Type> ptr;
};

が設定されている場合ptr、たとえばunique_ptrのデストラクタがオブジェクトの削除を処理します (存在する場合)。setPtrメソッドでは、関数reset()は古いインスタンス (存在する場合) を削除し、メンバーを提供された新しいインスタンス (または null - OK) に設定します。

次に、別の状況を比較します。

class X {
   // ...
   X() : ptr(new Type()) {}
   X(Type ptr) : ptr(ptr) {}
   // ...
   void setPtr(Type ptr2) {delete ptr; ptr = ptr2;}
   // ...
   Type* ptr;
};

同じ振る舞い?いいえ!ptr現在、安全な C++ コードを作成するには、 が破棄されたときに削除するデストラクタを追加で記述する必要があるためXです。

今いいよ?いいえ!共通のデストラクタがあるため、独自のコピー コンストラクタと代入演算子をロールアップ (またはブロック) する必要があるためです。そうしないと、X の 2 つのインスタンスが同じ Type オブジェクトを指すことになり、両方のインスタンスがここで彼らはこのインスタンスを所有しており、両方がいつかそれを削除しようとします。ドーン、アクセス違反。

ptrUnique_ptrは への強い参照とともに X オブジェクトを暗黙的にコピーすることを許可しません。-しかし、所有していないものを削除しようとしない限り、未加工の所有していないポインターがそれを指していても問題ありません!)。

これだけではありません。unique_ptr はコピーできませんが、移動コンストラクターと移動代入演算子が用意されています。したがって、関数などから安全に返すことができます。

これは、スマート ポインターのタイプ セーフが、より安全なコードの記述に変換される方法です。

黄金律: "delete" を記述しないようにしてください (独自のコンテナーまたはスマート ポインターを記述している場合を除く)。:)

于 2011-10-23T18:01:45.683 に答える
2

スタック上にすべてのオブジェクトを作成できる余裕がある場合は、auto_ptr. しかし、次のことを考えてください。

  • 関数からオブジェクトを返す (ローカルを返すことはできません)
  • 関数から返されたオブジェクトが呼び出し元によって受信されるか、例外が存在する場合に破棄されることを確認する
  • クラス内のオブジェクトへのポインターを集約します (デストラクタがそれを削除することを確認する必要があります。または、単にauto_ptrメモリ リークを防止するようにすることもできます)。
  • ...その他多数

考え直して、これについては Herb Sutter を読むべきでしょう。彼は私よりも多くのことを知っています。;-)

于 2011-10-23T17:57:43.887 に答える
1

これは正しい方法です:

void test()
{
    A a;
    std::auto_ptr<A> pA(new A);
    func(pA.get());
    std::cout << "end";
}

関数funcが例外をスローした場合、auto_ptrスコープ外になるとメモリが自動的に解放されます。

于 2011-10-23T17:58:09.680 に答える