具有可选所有权的智能指针

时间:2014-06-05 00:04:49

标签: c++ smart-pointers

我正在尝试允许一个类包含一个指针,它可以是一个拥有的指针或一个借来的指针。在前一种情况下,它应该破坏拥有的对象本身;在后一种情况下,它不应该破坏指向的对象。

在代码中,我有类A,B和C.我的目标是以下(简化)定义,其中B是需要拥有指针的类:

class C {
    ...
};

class B {
    C *c;
    B(C *c) : c(c) {
    }
};

class A {
    C c1;
    B b1, b2;
    // b2 leaks pointer to C
    A() : b1(&c1), b2(new C()) {
    }
};

A的实例破坏时,它会销毁c1b1b2。理想情况下,b2的销毁应删除匿名C实例,但b1的销毁不应删除任何内容(因为c1将直接被A销毁)。< / p>

我可以用什么样的智能指针来实现这一目标?或者,将所有权标志传递给B是最好的解决方案吗?

3 个答案:

答案 0 :(得分:1)

虽然我担心B可能会受到滥用,但您可以这样做:

class B {
    C *c;
    bool owned;

    B(C& c) : c(&c), owned(false) {}
    B(C *c) : c(c), owned(true) {}
    ~B() { if (owned) delete c; }
};

class A {
    C c1;
    B b1, b2;
    A() : b1(c1), b2(new C()) {}
};

答案 1 :(得分:1)

如果您确定并且可以保证重复使用的C不会被提前销毁(三重检查),那么有多种方法可以解决这个问题。
你可能会考虑一些:

  1. 您可以手动管理指针和标志。确保你获得了复制语义权利,例如像这样:

    class B {
        std::unique_ptr<C> c;
        bool shared = false;
    
        B(C& c) : c(&c), shared(true) {}
        B(C *c = 0) : c(c) {}
        ~B() { if (shared) c.release(); }
    };
    
  2. 您可以使用自定义删除器,如下所示:

    template <class T> struct maybe_delete
    {
        void operator()(T* p) const noexcept {if(!shared) delete p;}
        bool shared = false;
    };
    template <class T> struct maybe_delete<T[]>
    {
        void operator()(T* p) const noexcept {if(!shared) delete [] p;}
        template <class U> void operator()(U*) const = delete;
        bool shared = false;
    };
    
    class B {
        std::unique_ptr<C, maybe_delete> c;
    
        B(C& c) : B(&c) {this->c.get_deleter().shared = true;}
        B(C *c) : c(c) {}
    };
    
  3. 你可以看看std::shared_ptr,虽然这可能是严重的过度杀伤,可能会给你带来太多的开销。

答案 2 :(得分:0)

据我所知,没有副作用就无法归档此行为。如果它只是通常的指针(不是COM),那么你可以通过两个类中的shared_ptr访问C.如果只有B拥有C,那么他们两人都将被B&B的破坏所摧毁。如果A&amp; B拥有C,只有当最后剩下的活着所有者(无论是A还是B)被摧毁时,C才会被摧毁。

我知道这种做法要考虑所有权: 如果方法只是一个正常的指针,那意味着指针只会在该方法中使用。所以,B将是:

class B1 {
    B(C *c) {
      //do some staff with c
    }
    void doSomeStaff(C*) {}
};

或使用&amp; (更清洁,如果您的框架接受它):

class B2 {
    B(C& c) {
      //do some staff with c
    }
    void doSomeStaff(C&) {}
};

如果方法获得共享指针,则需要此指针以供将来重用(保留):

class B3 {
public:
    std::shared_ptr<C> c;
    B(std::shared_ptr<C> c) : c(c) {
    }
};

所以,现在你可以调用b1.doSomeStaff(b3.c)或b2.doSomeStaff(* b3.c)而不必考虑谁必须销毁指向的对象C.你只知道,这个对象将在b1中使用。这就是全部。

不要忘记指定您需要shared_ptr,而不是方法中的C * - shared_ptr是一个对象,它在复制时将引用计数增加到对象。而不是增量,但是当从C *。

构造时,创建一个引用count = 1的新shared_ptr

这不是您问题的答案,而是一些常见用途。请参阅Deduplicator中的unique_ptr。另请检查:http://www.boost.org/doc/libs/1_55_0/libs/smart_ptr/smart_ptr.htm。即使你不使用boost,也有一个很好的理论来使用不同的方法来保存对象。另请查看以下答案:What is a smart pointer and when should I use one?

相关问题