通过unique_ptr或值传递对象以及如何实现

时间:2015-10-17 14:21:04

标签: c++ c++11 data-structures parameter-passing smart-pointers

我有一个案例,我不确定是否应该使用unique_ptr或按值传递Object。

假设我有一个类A,它有一个B类向量,C类也有一个B类向量。每次我在C类中向Vector添加B对象时,都应该从C类向量中删除,反之亦然。当对象C被销毁时,B Vector类中的所有对象都应该添加到A类

中的B向量中
class B {
public:
    B();
    virtual ~B();
};

class A {
    C & c;
    std::vector<B> bs;
public:
    A(C & c ): c(c){};
    virtual ~A();
    void add(B b){
        bs.push_back(b);
        c.remove(b);
    }
    void remove(B b){
        bs.erase(std::remove(bs.begin(), bs.end(), b), bs.end());
    }
};

class C {
public:
     A & a;
    std::vector<B> bs;
    C(A & a): a(a) {

    };
    virtual ~C(){
        for (B b : bs) {
                a.add(b);
                remove(b);
            }
    }

    void add(B b){
        bs.push_back(b);
        a.remove(b);
    }
    void remove(B b){
        bs.erase(std::remove(bs.begin(), bs.end(), b), bs.end());
    }
};

我的问题:

  1. 在这种情况下使用指针会更好吗?我应该总是有一个独特的B对象!换句话说,如果两个b对象的内容不同,它们仍然不同,因为内存中的地址不同。
  2. 我想在C ++ 11中使用smart_pointers编写这段代码!哪种类型更好shared_ptrunique_ptr? B对象永远不会被两个对象拥有,而且它总是有一个所有者,所以我猜unique_ptr更好,但我不确定。
  3. 如何使用unique_ptr编写上面的代码?

2 个答案:

答案 0 :(得分:1)

  1. 如果复制构造B代价高昂,那么(智能)指针可能是一个好主意(重新设计应用程序逻辑可能是另一种解决方案),

  2. 如果我理解正确,给定的B实例始终由单个所有者操纵(AC)。 std::unique_ptr因此是合理的选择,

  3. 尝试以下实施方案。我没有编译它,但我认为你会得到一般的想法:)

  4. class B {
    public:
        B();
        virtual ~B();
    };
    
    class A {
        C & c;
        std::vector<std::unique_ptr<B>> bs;
    public:
        A(C & c ): c(c){};
        virtual ~A();
        // http://herbsutter.com/2013/06/05/gotw-91-solution-smart-pointer-parameters/
        // (c) Passing unique_ptr by value means "sink."
        void add(std::unique_ptr<B> b){
            c.remove(b);               // release the poiner from the other container
            bs.emplace_back(b.get());  // emplace the pointer in the new one
            b.release();               // emplacement successful. release the pointer
        }
        // http://herbsutter.com/2013/06/05/gotw-91-solution-smart-pointer-parameters/
        // (d) Passing unique_ptr by reference is for in/out unique_ptr parameters.
        void remove(std::unique_ptr<B>& b){
            // @todo check that ther returned pointer is != bs.end()
            std::find(bs.begin(), bs.end(), b)->release();             // first release the pointer
            bs.erase(std::remove(bs.begin(), bs.end(), b), bs.end());  // then destroy its owner
        }
    };
    
    class C {
    public:
        A & a;
        std::vector<std::unique_ptr<B>> bs;
        C(A & a): a(a) {
    
        };
        virtual ~C(){
            for (auto&& b : bs) {
                a.add(b);
                // a is going to call this->remove()...
                // unless calling this->remove() from "a"
                // while this is being destroyed is Undefined Behavior (tm)
                // I'm not sure :)
            }
        }
        // http://herbsutter.com/2013/06/05/gotw-91-solution-smart-pointer-parameters/
        // (c) Passing unique_ptr by value means "sink."
        void add(std::unique_ptr<B> b){
            c.remove(b);               // release the poiner from the other container
            bs.emplace_back(b.get());  // emplace the pointer in the new one
            b.release();               // emplacement successful. release the pointer
        }
        // http://herbsutter.com/2013/06/05/gotw-91-solution-smart-pointer-parameters/
        // (d) Passing unique_ptr by reference is for in/out unique_ptr parameters.
        void remove(std::unique_ptr<B>& b){
            // @todo check that ther returned pointer is != bs.end()
            std::find(bs.begin(), bs.end(), b)->release();             // first release the pointer
            bs.erase(std::remove(bs.begin(), bs.end(), b), bs.end());  // then destroy its owner
        }
    };
    

答案 1 :(得分:1)

如果必须,我只会使用public function User($arg) { switch($arg) { case "online": return self::CheckKey(); // < -- At the start of this line. break; } } 。您可能希望unique_ptr仅限移动类型(例如B)来限制所有权。

如果unique_ptr移动费用昂贵,或者阻止复制B是不切实际的,请使用B,但要注意您正在为动态内存分配付费。< / p>

以下是在受代码启发的示例中,如何使用仅限移动unique_ptr。如果您使用B,则它应该完全相同:

unique_ptr

Live demo.