实现智能指针 - 使用模板进行动态分配

时间:2009-08-22 01:01:33

标签: c++ smart-pointers

我正在编写一个智能指针countingptr并且我遇到了减速带。 countsptr的基本功能是像任何其他智能指针一样工作,并且还有一个指向单个对象的指针数。到目前为止,代码是:

[解决]

#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);

然后我得到一个编译器错误,说“请求成员'指针'在'*(&amp; one) - &gt; counts_ptr :: operator-&gt ;,T = double',这是非类型double”。

我考虑过做一个函数来做这个,虽然我可以创建一个函数来分配一个T的数组,但我想不出一种方法来分配实际的对象。感谢任何帮助。谢谢。

6 个答案:

答案 0 :(得分: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; } }

新解决方案

如果你想重新计算一个counts_ptr(例如one = new double(5))以更新所有相关的counted_ptr,将指针和计数都放在一个帮助器类中,让你的指针类保存指向帮助类(你可能已经走了这条路)。您可以通过两种方式填写此设计:

  1. 使辅助类成为一个简单的结构(和一个私有内部类),并将所有逻辑放在外部类方法中
  2. 使counted_ptr成为助手类。 counted_ptr维护引用计数但不会自动更新计数;它不是智能指针,只响应releaseretain消息。如果您完全熟悉Objective-C,那么它基本上就是传统的内存管理(autoreleasing除外)。当引用计数达到0(与Obj-C的另一个潜在差异)时,counted_ptr可能会也可能不会自行删除。 counted_ptr不应该是可复制的。目的是对于任何普通指针,最多应该有一个counted_ptr

    创建一个smart_ptr类,该类具有指向counted_ptr的指针,该指针在应该保存相同普通指针的smart_ptr个实例之间共享。 smart_ptr负责通过发送counted_ptr版本并保留方法来自动更新计数。

    counted_ptr可能是也可能不是shared_ptr的私人内部类。

  3. 这是选项二的界面。因为你这是一个练习,我会让你填写方法定义。潜在的实现类似于已经发布的内容,除了您不需要counted_ptr的复制构造函数和复制赋值运算符,counted_ptr::~counted_ptr不会调用counted_ptr::release({{1} {}}的工作和smart_ptr::~smart_ptr可能不会释放counted_ptr::release(你可能会把它留给析构函数)。

    counted_ptr::_pointer

    希望上面唯一含糊不清的是故意的。

答案 1 :(得分:2)

(对不起,新手在这里,不能发表评论)。 Adatapost补充道,“one=new double(5);”应该有效。但是需要另外一个改变:引用计数需要一些帮助。

...
~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;
        }
    }

答案 2 :(得分: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成员。

答案 3 :(得分:1)

由于眼前问题已经解决,我想提供更长远的问题:

当您继续开发此代码时,您肯定希望提供有经验的程序员(无论是在这里还是其他地方)进行全面审核。你发布它时代码有一些明显的问题,虽然outis帮助纠正了它们。但是,即使您的代码全部编译并且似乎在您自己的测试中工作,也可能存在您尚未学会思考的测试和情境。智能指针很容易出现微妙的问题,直到非常具体的情况才会出现。因此,您希望其他人查看您的代码,以找到您可能错过的任何内容。

请不要将此视为对您当前代码的任何侮辱。我只是提供友好建议,以确保您从这个项目中学到最多。

答案 4 :(得分:0)

除非您出于学术原因而未执行此操作,否则您可能需要考虑使用boost::shared_ptr {{1}}成员。它不是完全有效,但它确实有效,你最好使用经过良好测试,成熟和线程安全的东西。如果您是出于学习目的而这样做,请务必在use_count()中查看参考计数和智能指针的处理方法。

答案 5 :(得分:0)

在覆盖之前,您需要递减计数并可能删除指向operator =中旧值的指针。你还需要“删除指针”,以避免泄漏内存