C++ 具有可选所有权的智能指针
我试图允许一个类包含一个指针,它可以是一个拥有的指针,也可以是一个借用的指针。在前一种情况下,它应该销毁所拥有的对象本身;在后一种情况下,它不应该破坏指向的对象 在代码中,我有类A、B和C。我的目标是以下(简化)定义,其中B是需要拥有指针的类:C++ 具有可选所有权的智能指针,c++,smart-pointers,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 poin
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
的实例销毁时,它会销毁c1
、b1
和b2
。理想情况下,b2
的销毁应删除匿名C
实例,但b1
的销毁不应删除任何内容(因为c1
将由A直接销毁)
我可以使用什么样的智能指针来实现这一点?或者,最好的解决方案是将所有权标志传递给B吗?虽然我担心
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()) {}
};
如果您确信并且能够保证重复使用的
C
不会被提前销毁(三次检查),那么有多种方法可以做到这一点。您可能会考虑:
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(); }
};
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) {}
};
B类{
std::唯一的ptr c;
bool shared=false;
B(C&C):C&C,共享(真){}
B(C*C=0):C(C){}
~B(){if(共享)c.release();}
};
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(); }
};
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) {}
};
模板结构可能\u删除
{
void操作符()(T*p)const noexcept{if(!shared)delete p;}
bool shared=false;
};
模板结构可能会被删除
{
void操作符()(T*p)const noexcept{if(!shared)delete[]p;}
模板无效运算符()(U*)常量=删除;
bool shared=false;
};
B类{
std::唯一的ptr c;
B(C&C):B(&C){this->C.get_deleter().shared=true;}
B(C*C):C(C){}
};
据我所知,没有办法在没有副作用的情况下归档这种行为。如果只是普通的指针(不是COM),那么您可以通过两个类中的共享ptr访问C。如果只有B拥有C,那么他们两个都将被B的毁灭所摧毁。如果两个A&B都拥有C,那么C只有在最后一个活着的所有者(无论是A还是B)被销毁时才会被销毁 我知道这种做法是为了考虑所有权: 若方法只得到一个普通指针,则意味着该指针将仅在该方法内部使用。因此,B将是:
class B1 {
B(C *c) {
//do some staff with c
}
void doSomeStaff(C*) {}
};
或者使用&(如果您的框架接受,则使用cleaner):
如果方法获得共享指针,则需要该指针以备将来重用(保留):
B3级{
公众:
std::共享的ptr c;
B(std::shared_ptr c):c(c){
}
};
因此,现在您可以调用b1.doSomeStaff(b3.c)或b2.doSomeStaff(*b3.c),而无需考虑谁必须销毁指向的对象c。您只知道,此对象将在b1中使用。就这些
不要忘记指定您需要的是shared_ptr,而不是方法中的C*——shared_ptr是一个对象,它在复制时会增加对对象的引用计数。并不是递增,而是在从C*构造时创建一个引用计数为1的新共享_ptr
这不是你问题的答案,而是一些常见的用途。请参见答案中重复数据消除程序中的unique_ptr。另请检查:。即使不使用boost,也有一个很好的理论可以用来使用不同的方法来保持对象。同时检查以下答案:听起来像是噩梦。你如何解释这种“可选所有权”?指针对象是您独有的,还是您与其他人共享?线程安全?再进入者?还是你的一切?
std::shared_ptr
甚至允许这些恶作剧。但是如果与默认的deleter不同,您必须手动设置适当的deleter,比如空deleter。或者,使用一个指向所属对象的共享\u ptr
,以获得完全正确的语义。@重复数据消除程序删除程序是一个模板参数,因此您必须编写一个处理这两种情况的删除程序。你不能在一种情况下只传递一个空的删除器,在另一种情况下传递一个常规的删除器。要回答这个问题,“最好的解决方案是只传递一个所有权标志给B吗?”。是。@Adam:如何构造共享\u ptr
的决定与传递所有权标志resp相同。更好的方法是按照我的第二种方式来构建它。