3

私はスマート ポインター countptr を作成している最中で、スピード バンプにぶつかりました。countptr の基本的な機能は、他のスマート ポインターと同じように機能し、1 つのオブジェクトを指しているポインターの数をカウントすることです。これまでのところ、コードは次のとおりです。

[解決済み]

#include "std_lib_facilities.h"

template <class T>
class counted_ptr{
private:
    T* pointer;
    int* count;

public:
    counted_ptr(T* p = 0, int* c = new int(1)) : pointer(p), count(c) {}    // default constructor
    explicit counted_ptr(const counted_ptr& p) : pointer(p.pointer), count(p.count) { ++*count; } // copy constructor
    ~counted_ptr() { --*count; delete pointer; }

    counted_ptr& operator=(const counted_ptr& p)
    {
        pointer = p.pointer;
        count = p.count;
        ++*count;
        return *this;
    }
    T* operator->() const{ return pointer; }
    T& operator*() const { return *pointer; }

    int Get_count() const { return *count; }
};


int main()
{
    counted_ptr<double> one;
    counted_ptr<double>two(one);
    int a = one.Get_count();
    cout << a << endl;
}

私が何かをしようとすると

one->pointer = new double(5);

次に、「'*(&one)->counted_ptr::operator->with T = double' のメンバー 'pointer' を要求します。これは非クラス型 double です」というコンパイラ エラーが発生します。

これを行う関数を作成することを検討しましたが、T の配列を割り当てる関数を作成できましたが、実際のオブジェクトを割り当てる関数を作成する方法が思いつきません。どんな助けでも大歓迎です、ありがとう。

4

6 に答える 6

5

古いソリューション

別の代入演算子はどうですか?

counted_ptr& counted_ptr::operator=(T* p)
{
    if (! --*count) { delete count; }
    pointer = p;
    count = new int(1);
    return *this;
}

...

one = new double(5);

また、デストラクタは常に共有ポインタを削除します。これがおそらく *one がランダムな番号になる原因です。おそらく、次のようなものが必要です。

counted_ptr::~counted_ptr() { if (! --*count) { delete pointer; delete count; } }

新しいソリューション

one = new double(5)関連するすべての s を更新するためにcount_ptr (例: ) を再ポイントする必要があるcounted_ptrため、ポインターとカウントの両方をヘルパー クラスに配置し、ポインター クラスにヘルパー クラスへのポインターを保持させます (既にこのパスをたどっている可能性があります)。このデザインに記入するには、次の 2 つの方法があります。

  1. ヘルパー クラスを単純な構造体 (およびプライベート 内部クラス) にし、すべてのロジックを外部クラス メソッドに配置します。
  2. ヘルパーcounted_ptrクラスを作成します。counted_ptr参照カウントを維持しますが、カウントを自動的に更新しません。releaseこれはスマート ポインターではなく、メッセージにのみ応答しretainます。Objective-C に少しでも精通している場合、これは基本的に従来のメモリ管理 (自動解放は別として) です。counted_ptr参照カウントが 0 に達したときに自身を削除する場合としない場合があります (Obj-C との別の潜在的な違い)。counted_ptrs はコピー可能であってはなりません。その意図は、単純なポインターの場合、最大で 1 つある必要があるということcounted_ptrです。

    smart_ptrへのポインターを持つクラスを作成します。これは、同じプレーン ポインターを保持することになっているインスタンスcounted_ptr間で共有されます。release メソッドと keep メソッドを送信して、カウントを自動的に更新する責任があります。smart_ptrsmart_ptrcounted_ptr

    counted_ptrのプライベート内部クラスである場合とそうでない場合がありshared_ptrます。

オプション 2 のインターフェイスを次に示します。これは演習として行っているので、メソッド定義を記入させてください。counted_ptr潜在的な実装は、 のコピー コンストラクターとコピー代入演算子が必要ないこと、counted_ptr::~counted_ptr呼び出しを行わないことcounted_ptr::release(それがsmart_ptr::~smart_ptr仕事です)、counted_ptr::release解放counted_ptr::_pointerされないこと (デストラクタに任せる場合があります)を除いて、既に投稿されているものと似ています。.

// counted_ptr owns its pointer an will free it when appropriate.
template <typename T>
class counted_ptr {
private:
    T *_pointer;
    size_t _count;

    // Make copying illegal
    explicit counted_ptr(const counted_ptr&);
    counted_ptr& operator=(const counted_ptr<T>& p);

public:
    counted_ptr(T* p=0, size_t c=1);
    ~counted_ptr();

    void retain();        // increase reference count.
    bool release();       // decrease reference count. Return true iff count is 0
    void reassign(T *p);  // point to something else.
    size_t count() const;

    counted_ptr& operator=(T* p);

    T& operator*() const;
    T* operator->() const;
};

template <typename T>
class smart_ptr {
private:
    counted_ptr<T> *_shared;
    void release();  // release the shared pointer
    void retain();   // retain the shared pointer

public:
    smart_ptr(T* p=0, int c=1);   // make a smart_ptr that points to p
    explicit smart_ptr(counted_ptr<T>& p); // make a smart_ptr that shares p
    explicit smart_ptr(smart_ptr& p); // copy constructor
    ~smart_ptr();

    // note: a smart_ptr's brethren are the smart_ptrs that share a counted_ptr.
    smart_ptr& operator=(smart_ptr& p); /* Join p's brethren. Doesn't alter pre-call
        * brethren. p is non-const because this->_shared can't be const. */
    smart_ptr& operator=(counted_ptr<T>& p);  /* Share p. Doesn't alter brethren. 
        * p is non-const because *this isn't const. */
    smart_ptr& operator=(T* p); // repoint this pointer. Alters brethren

    size_t count() const; // reference count

    T& operator*() const;  // delegate these to _shared
    T* operator->() const;

};

うまくいけば、上記のあいまいな点は意図的なものだけです。

于 2009-08-22T01:48:41.417 に答える
2

(申し訳ありませんが、初心者であり、コメントを残すことはできません)。Adatapost が追加したもの " one=new double(5);" が機能するはずです。ただし、もう 1 つ変更が必要です。参照カウントには少し助けが必要です。

...
~counted_ptr() {
    --*count; 
    // deallocate objects whose last reference is gone.
    if (!*count) 
    {   
        delete pointer;
        delete count;
    }
}

counted_ptr& operator=(const counted_ptr& p)
{
    // be careful to accommodate self assignment
    ++*p.count;

    // may lose a reference here
    --*count;
    if (!*count)
    {
        delete pointer;
        delete count;
    }

    count=p.count;
    pointer=p.pointer;
    return *this;
}

もちろん、ここにはコードの繰り返しがあります。そのコードを独自の関数にリファクタリングすることは理にかなっているかもしれません。

private:
    /** remove our reference */
    void release()
    {
        --*count;
        if (!*count)
        {
            delete pointer;
            delete count;
        }
    }
于 2009-08-22T01:52:15.360 に答える
1

もしかして、「one.pointer=new double(5);」のことですか?"" と書くとone->pointer=new double(5);が呼び出されますcounted_ptr<double>::operator->。つまり、次とほぼ同等です。

double *tmp = one.operator->(); // returns one.pointer
tmp->pointer = new double(5);

ただし、ダブル ポインターは構造体ではないため、メンバーはありませんpointer

于 2009-08-22T01:17:28.477 に答える
0

上書きする前に、カウントをデクリメントし、場合によっては operator = の古い値へのポインターを削除する必要があります。また、メモリリークを避けるために、「削除ポインタ」がある場所ならどこでも「削除カウント」が必要です

于 2009-08-22T02:21:48.297 に答える
0

学術的な理由でこれを行っていない場合を除き、 のuse_count()メンバーの使用を検討することをお勧めしますboost::shared_ptr。完全に効率的というわけではありませんが、機能するので、十分にテストされ、成熟した、スレッドセーフなものを使用することをお勧めします。学習目的でこれを行っている場合は、参照カウントとスマート ポインターの処理をより効果的な C++で確認してください。

于 2009-08-22T01:57:47.677 に答える