C++ 按唯一性或值传递对象以及如何实现

C++ 按唯一性或值传递对象以及如何实现,c++,c++11,data-structures,parameter-passing,smart-pointers,C++,C++11,Data Structures,Parameter Passing,Smart Pointers,我有一个案例,我不确定是否应该使用unique\u ptr或通过值传递对象 假设A类有一个B类向量,C类也有一个B类向量。每次我在C类的向量中添加一个B对象时,它应该从C类的向量中删除,反之亦然。当对象C被销毁时,B向量类中的所有对象都应添加到A类中的B向量中 class B { public: B(); virtual ~B(); }; class A { C & c; std::vector<B> bs; public: A(C

我有一个案例,我不确定是否应该使用
unique\u ptr
或通过值传递对象

假设A类有一个B类向量,C类也有一个B类向量。每次我在C类的向量中添加一个B对象时,它应该从C类的向量中删除,反之亦然。当对象C被销毁时,B向量类中的所有对象都应添加到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());
    }
};
B类{
公众:
B();
虚拟~B();
};
甲级{
C&C;
std::向量bs;
公众:
A(C&C):C(C){};
虚拟~A();
无效添加(B){
b.推回(b);
c、 删除(b);
}
清除空洞(B){
擦除(std::remove(bs.begin(),bs.end(),b),bs.end());
}
};
C类{
公众:
A&A;
std::向量bs;
C(A&A):A(A){
};
虚拟~C(){
(B:bs){
a、 添加(b);
删除(b);
}
}
无效添加(B){
b.推回(b);
a、 删除(b);
}
清除空洞(B){
擦除(std::remove(bs.begin(),bs.end(),b),bs.end());
}
};
我的问题是:

  • 在这种情况下使用指针更好吗?我应该总是有一个独特的对象为B!换句话说,如果两个b对象的内容不同,它们仍然不同,因为内存中的地址不同
  • 我想用C++ 11中的StaskId指针来编写这个代码!哪种类型更好
    共享\u ptr
    还是
    唯一\u ptr
    ?B对象从来不是两个对象的所有者,它总是有一个所有者,所以我想
    unique\u ptr
    更好,但我不确定
  • 如何使用unique\u ptr编写上述代码?
  • 如果复制构造
    B
    成本高昂,那么(智能)指针可能是一个好主意(重新设计应用程序逻辑可能是另一个解决方案)

  • 如果我理解正确,一个给定的
    B
    实例总是由一个所有者操纵(要么
    a
    要么
    C
    )<因此,code>std::unique_ptr是一个合理的选择

  • 尝试以下实现。我还没有编译它,但我想你会明白大意:)

  • B类{
    公众:
    B();
    虚拟~B();
    };
    甲级{
    C&C;
    std::向量bs;
    公众:
    A(C&C):C(C){};
    虚拟~A();
    // http://herbsutter.com/2013/06/05/gotw-91-solution-smart-pointer-parameters/
    //(c)通过值传递唯一的_ptr意味着“接收器”
    无效添加(标准::唯一\u ptr b){
    c、 移除(b);//从另一个容器中释放poiner
    bs.emplace_back(b.get());//将指针放置在新指针中
    b、 release();//安放成功。释放指针
    }
    // http://herbsutter.com/2013/06/05/gotw-91-solution-smart-pointer-parameters/
    //(d)通过引用传递unique_ptr用于输入/输出unique_ptr参数。
    无效删除(标准::唯一的ptr&b){
    //@todo检查返回的指针是否为!=bs.end()
    std::find(bs.begin(),bs.end(),b)->release();//首先释放指针
    bs.erase(std::remove(bs.begin(),bs.end(),b),bs.end());//然后销毁它的所有者
    }
    };
    C类{
    公众:
    A&A;
    std::向量bs;
    C(A&A):A(A){
    };
    虚拟~C(){
    用于(自动和b:bs){
    a、 添加(b);
    //a将调用此->删除()。。。
    //除非从“a”调用此->删除()
    //当这被销毁时是未定义的行为(tm)
    //我不确定:)
    }
    }
    // http://herbsutter.com/2013/06/05/gotw-91-solution-smart-pointer-parameters/
    //(c)通过值传递唯一的_ptr意味着“接收器”
    无效添加(标准::唯一\u ptr b){
    c、 移除(b);//从另一个容器中释放poiner
    bs.emplace_back(b.get());//将指针放置在新指针中
    b、 release();//安放成功。释放指针
    }
    // http://herbsutter.com/2013/06/05/gotw-91-solution-smart-pointer-parameters/
    //(d)通过引用传递unique_ptr用于输入/输出unique_ptr参数。
    无效删除(标准::唯一的ptr&b){
    //@todo检查返回的指针是否为!=bs.end()
    std::find(bs.begin(),bs.end(),b)->release();//首先释放指针
    bs.erase(std::remove(bs.begin(),bs.end(),b),bs.end());//然后销毁它的所有者
    }
    };
    
    如果必须,我只会使用
    unique\u ptr
    。您可能更喜欢将
    B
    设置为仅移动类型(如
    唯一\u ptr
    ),以限制所有权

    如果移动
    B
    的成本很高,或者防止复制
    B
    是不切实际的,那么请使用
    unique\u ptr
    ,但请注意,您需要为动态内存分配付费

    下面是如何在一个受代码启发的示例中使用仅移动
    B
    。如果改用
    unique\u ptr
    ,其工作原理应完全相同:

    struct B {
        B();
        B(B&&) = default;                 // Explicitly default the 
        B& operator=(B&&) = default;      // move functions.
    
        B(const B&) = delete;             // Delete copy functions - Not strictly 
        B& operator=(const B&) = delete;  // necessary but just to be explicit.
    };
    
    struct A {
        std::vector<B> bs;
        void add(B b){
            bs.push_back(std::move(b));
        }
        B remove(std::vector<B>::iterator itr){
            B tmp = std::move(*itr);
            bs.erase(itr);
            return tmp;
        }  
    };
    
    struct C {
        A& a;
        std::vector<B> bs;
        C(A& a) : a(a) {}
    
        ~C(){
            for (auto& b : bs) {
                a.add(std::move(b));
            }
        }  // bs will be deleted now anyway, no need to remove the dead objects
    
        void add(B b){
            bs.push_back(std::move(b));
        }
        B remove(std::vector<B>::iterator itr){
            auto tmp = std::move(*itr);
            bs.erase(itr);
            return tmp;
        }
    };
    
    int main() {
        A a;
        C c(a);
        a.add(B());
        auto tmp = a.remove(a.bs.begin());
        c.add(std::move(tmp));
    }
    
    结构B{ B(); B(B&&)=default;//显式默认 B&operator=(B&&)=默认值;//移动函数。 B(const B&)=delete;//删除复制函数-不严格 B&operator=(const B&)=delete;//这是必需的,但只是为了明确起见。 }; 结构A{ std::向量bs; 无效添加(B){ b.推回(标准::移动(b)); } B删除(std::vector::迭代器itr){ B tmp=std::move(*itr); 擦除(itr); 返回tmp; } }; 结构C{ A&A; std::向量bs; C(A&A):A(A){} ~C(){ 适用于(汽车和早餐:英国标准){ a、 添加(标准::移动(b)); } }//无论如何,bs现在将被删除,无需删除死掉的对象 无效添加(B){ b.推回(标准::移动(b)); } B删除(std::vector::迭代器itr){ 自动tmp=std::move(*itr);
    struct B {
        B();
        B(B&&) = default;                 // Explicitly default the 
        B& operator=(B&&) = default;      // move functions.
    
        B(const B&) = delete;             // Delete copy functions - Not strictly 
        B& operator=(const B&) = delete;  // necessary but just to be explicit.
    };
    
    struct A {
        std::vector<B> bs;
        void add(B b){
            bs.push_back(std::move(b));
        }
        B remove(std::vector<B>::iterator itr){
            B tmp = std::move(*itr);
            bs.erase(itr);
            return tmp;
        }  
    };
    
    struct C {
        A& a;
        std::vector<B> bs;
        C(A& a) : a(a) {}
    
        ~C(){
            for (auto& b : bs) {
                a.add(std::move(b));
            }
        }  // bs will be deleted now anyway, no need to remove the dead objects
    
        void add(B b){
            bs.push_back(std::move(b));
        }
        B remove(std::vector<B>::iterator itr){
            auto tmp = std::move(*itr);
            bs.erase(itr);
            return tmp;
        }
    };
    
    int main() {
        A a;
        C c(a);
        a.add(B());
        auto tmp = a.remove(a.bs.begin());
        c.add(std::move(tmp));
    }