6

私のクレイジーなAutoArrayの話に戻ります...(そこから重要なビットを引用します:

class AutoArray
{
    void * buffer;
public:
    //Creates a new empty AutoArray
    AutoArray();
    //std::auto_ptr copy semantics
    AutoArray(AutoArray&); //Note it can't be const because the "other" reference
                           //is null'd on copy...
    AutoArray& operator=(AutoArray);
    ~AutoArray();
    //Nothrow swap
    // Note: At the moment this method is not thread safe.
    void Swap(AutoArray&);
};

)

とにかく、コピーコンストラクターを実装しようとしています。次のようなクライアント コードがあります (ビルドされないため、まだ bitbucket にコミットされていません)。

AutoArray NtQuerySystemInformation(...) { ... };

AutoArray systemInfoBuffer = NtQuerySystemInformation(...);

コピー コンストラクターが非参照を引数として取るため、これは失敗します .... しかし、代入で使用されるソースが変更されていることを考えると、参照constを取るようにコピー コンストラクターを変更する方法がわかりません(したがって、ではない)。もちろん、値渡しを使用するように変更することはできません。これはコピー コンストラクターであり、無限ループになるからです。constAutoArrayconst

を使用していた場合auto_ptr、これは有効です。

std::auto_ptr NtQuerySystemInformation(...) { ... };

std::auto_ptr systemInfoBuffer = NtQuerySystemInformation(...);

では、どのようにしてauto_ptrのコピー セマンティクスを持つクラスが可能になるのでしょうか?

4

3 に答える 3

14

auto_ptr汚いトリックを使用します。

auto_intテンプレートや継承によってもたらされる複雑さをもたらすことなく、コピー構築機能だけを示すために名前が付けられたダムダウンされたクラスを使用します。コードはほとんど正しいと思いますが、テストされていません。基本的なauto_int外観は次のようになります。

class auto_int
{
public:

    auto_int(int* p = 0) : p_(p) { }

    ~auto_int() { delete p_; }

    // copy constructor taking a non-const reference:
    auto_int(auto_int& other) 
        : p_(other.release()) { }

    int* release() 
    {
        int* temp = p_;
        p_ = 0;
        return temp;
    }

private:

    int* p_;
};

この基本auto_intでは、一時オブジェクトをコピーすることはできません。私たちの目標は、次のようなものを書くことができるようにすることです。

auto_int p(auto_int(new int()));

私たちにできることは、ヘルパークラスを使用することです。の場合auto_ptr、これはと呼ばれauto_ptr_refます。私たちは私たちのものと呼びますauto_int_ref

class auto_int;

class auto_int_ref 
{
public:
    auto_int_ref(auto_int* p) : p_(p) { }

    auto_int& ref() { return *p_; }

private:
    auto_int* p_;
};

基本的に、このクラスのインスタンスは、へのポインタを格納し、auto_intそれをへの「参照」として使用できるようにしますauto_int

次に、auto_intクラスでは2つの追加関数が必要です。をとる別のコンストラクターが必要であり、暗黙的に:に変換auto_int_refできる変換演算子が必要です。auto_intauto_int_ref

auto_int(auto_int_ref other)
    : p_(other.ref().release()) { }

operator auto_int_ref() { return this; }

これにより、コピーコンストラクターに非定数参照を取得させながら、一時的なものを「コピー」することができます。サンプルコードをもう一度見ると、次のようになります。

auto_int p(auto_int(new int()));

何が起こるかというと、新しい一時的なものを作成し、をとるコンストラクターにauto_int渡します。次に、この一時的なものは、を使用してそれを指すに変換され、をとるコンストラクターがを初期化するために使用されます。new int()int*auto_int_refoperator auto_int_ref()auto_intauto_int_refp

于 2010-12-22T22:14:03.353 に答える
3

auto_ptrのコピーコンストラクタは、渡されたオブジェクトから所有権を奪うことによって機能します。これは、または他のSTLコレクションauto_ptrで使用できない理由の大きな部分でもあります。vector

これは、ほとんどのコピーコンストラクターの動作方法ではありません。通常、コピーコンストラクターは渡されたオブジェクトのクローンを作成するだけなので、const参照を渡すことができます。しかし、auto_ptrこれはしません。実際に元のオブジェクトを変更しました。この意味で、セマンティクスではなく、名前による唯一のコピーコンストラクターです。

EDIT2:

私はこれを少し煮詰めようとしています。したがって、効果的に、次のような構文を可能にする何かをクラスで実行しようとしています。

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

auto_ptr<string> gimme()
{
    return auto_ptr<string>(new string("Hello"));
}

int main()
{
    auto_ptr<string> s = gimme();
}

...そしてあなたはそのs = gimme()部品をどのように機能させるのか疑問に思っています。右?

ここでの秘密はauto_ptr_ref、20.4.5の標準で説明されているプロキシクラスにあります。その目的は、「auto_ptrオブジェクトを関数に渡したり関数から返したりできるようにすること」です。

namespace std {
  template <class Y> struct auto_ptr_ref {};
  template<class X> class auto_ptr {
  public:
    typedef X element_type;

    // 20.4.5.1 construct/copy/destroy:
    explicit auto_ptr(X* p =0) throw();
    auto_ptr(auto_ptr&) throw();
    template<class Y> auto_ptr(auto_ptr<Y>&) throw();
    auto_ptr& operator=(auto_ptr&) throw();
    template<class Y> auto_ptr& operator=(auto_ptr<Y>&) throw();
    auto_ptr& operator=(auto_ptr_ref<X> r) throw();
    ˜auto_ptr() throw();
    // 20.4.5.2 members:
    X& operator*() const throw();
    X* operator->() const throw();
    X* get() const throw();
    X* release() throw();
    void reset(X* p =0) throw();
    // 20.4.5.3 conversions:
    auto_ptr(auto_ptr_ref<X>) throw();
    template<class Y> operator auto_ptr_ref<Y>() throw();
    template<class Y> operator auto_ptr<Y>() throw();
  };
}
于 2010-12-22T22:05:15.630 に答える
0

T*からへの暗黙の変換はありませんstd::auto_ptr<T>NTSTATUSハンドルからへの暗黙の変換コンストラクターがあると思いますAutoArray。ただし、その変換によって一時的なものが作成された場合、その一時的なものはコピーできません。

コピー初期化ではなく直接初期化を使用すると、「問題」がなくなる可能性があります。

AutoArray systemInfoBuffer( ntDll.NtQuerySystemInformation(
  Dll::NtDll::SystemProcessInformation) );
于 2010-12-22T22:13:33.733 に答える