1

我有一个 A 类,它有一个指向 B 类的指针作为它的字段之一:

class A {
private:
    B *ptr;
public:
    A(B*);
    A();
    ~A();
}

A::A(B *ptr)
{
    this->ptr = ptr;
}

A::A()
{
    this->ptr = new B();
}

A::~A()
{
    delete this->ptr;
}

我希望析构函数仅在由 new 分配的情况下删除 B,我只能通过设置一个存储指针原点的标志来执行此操作(因此,只有在 A 的构造期间分配了 ptr 时才调用 delete),还是有更优雅的解决方案,即,我可以在任何指针上调用 delete (我知道如果传入的指针是使用 new 分配的,它也将被删除,但是如果指针是从范围传入哪个 A 的构造函数被调用,显然删除 this 是未定义的)?

4

4 回答 4

3

还是有更优雅的解决方案

不,不是真的;需要清楚地记录谁拥有这个指针。看起来你的课是这样的,所以你可以自己构建ptr吗?

#include <memory>

class A {
private:
    std::unique_ptr<B> ptr;
public:
    A(some_data args) 
        : ptr(new B(args)) { };
    A();    
}

如果您的类不拥有也可以的指针,请不要释放它。否则,您将需要在外部设置一个标志(即,dealloc_on_destruct)以知道该做什么,这可能会变得混乱。

于 2012-09-17T17:15:10.950 回答
3

更优雅的解决方案是没有具有不同所有权模型的类,在这种情况下,拥有与不属于你的类。不要在同一个类类型中混合这两个想法,因为它只会让你的用户/客户感到困惑(违反最小意外原则)。

要么创建具有您需要的不同行为的单独类,要么选择所有权模型并强制您的客户坚持使用它(在非默认构造函数中传递和转移所有权,或者不允许自我分配)。

于 2012-09-17T17:18:34.167 回答
1

除了其他人所说的(避免这种设计):如果你绝对不能避免这种设计,并且你需要这个有趣的类,有时拥有它B,有时不拥有它,它取决于调用哪个构造函数,那么你可以像这样使用unique_ptr(或shared_ptr):

void delete_it(B*) { std::default_delete<B>()(t); }
void do_nothing(B *t) {}

class A {
    unique_ptr<B, void(*)(B*)> ptr;
  public:
    A(B *ptr) ptr(ptr, do_nothing) {}
    A() ptr(new B(), delete_it) {}
    // no need for destructor
    // hence also no need to worry about copy constructor or assignment
};

它比“原始指针加标志”更好的原因是您避免了必须实现删除器和复制(并在 C++11 中移动)。就性能而言,它可能比“原始指针加标志”更糟糕,但大多数时候您不必担心这一点。如果有正当理由,你可以回来做额外的工作。您不需要更改要切换的类的源接口,尽管它可能会破坏二进制兼容性。

于 2012-09-17T17:49:01.860 回答
1

仅使用您提供的代码无法回答该问题。真正的问题是为什么您可以接受或不接受指针,以及如果将指针传递给您,谁拥有内存。

根据您的对象在您的特定域中应该做什么,可以采取不同的替代方案。例如,如果您可以与调用者共享所有权,那么您应该使用 a shared_ptr,如果您将保留对象中的所有权,您应该使用 aunique_ptr在界面中明确说明您的对象将获取所有权。如果不共享所有权,则考虑传递对对象的引用(即使您在内部存储了一个指针),在这种情况下,您可以将所有权与实际使用分开:

// option 1: shared ownwership
class A {
   std::shared_ptr<B> ptr;
public:
   A( std::shared_ptr<B> const & p ) : ptr(p) {}
   A() : ptr( std::make_shared<B>() ) {}
};
// option 2: grab ownership
class A {
   std::unique_ptr<B> ptr;
public:
   A( std::unique_ptr<B> p ) : ptr( std::move(p) ) {}
   A() : ptr( new B(); }
};
// option 3: no ownership (unless we create the object)
// (separating concerns: ref to access the object, ptr to manage it)
class A {
   std::unique_ptr<B> ptr;   // only ownership
   B * ref;
public:
   A( B & b ) : ptr(), ref(&b) {}
   A() : ptr( new B() ), ref(ptr.get()) {}
   // Internally use 'ref' to access the object the destructor will delete it 
   // if needed
};
于 2012-09-17T17:28:30.933 回答