我正在尝试允许一个类包含一个指针,它可以是一个拥有的指针或一个借来的指针。在前一种情况下,它应该破坏拥有的对象本身;在后一种情况下,它不应该破坏指向的对象。
在代码中,我有类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
的实例破坏时,它会销毁c1
,b1
和b2
。理想情况下,b2
的销毁应删除匿名C
实例,但b1
的销毁不应删除任何内容(因为c1
将直接被A销毁)。< / p>
我可以用什么样的智能指针来实现这一目标?或者,将所有权标志传递给B是最好的解决方案吗?
答案 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
不会被提前销毁(三重检查),那么有多种方法可以解决这个问题。
你可能会考虑一些:
您可以手动管理指针和标志。确保你获得了复制语义权利,例如像这样:
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) {}
};
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?