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());
}
};
我的问题是:
共享\u ptr
还是唯一\u ptr
?B对象从来不是两个对象的所有者,它总是有一个所有者,所以我想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));
}