2016-07-25 97 views
0

我有一个简单的容器类,指向一个抽象类,我有函数来获取/设置容器类中的指针。更具体地说,这个类看起来像这样:C++将抽象类的派生对象添加到另一个类中而没有悬挂指针?

class Container 
{ 
    Abstract* thing; 
public: 
    void set(Abstract &obj) 
    { 
     thing = &obj; //danger of dangling pointer 
    } 

    Abstract* get() 
    { 
     return thing; 
    } 
}; 

Abstract是一个抽象类。如已经看到的那样,存在悬挂指针的危险。我知道我可以制作一个对象(新)的副本,然后指向它。但是我不能创建一个抽象类的实例。有什么解决方案?


以下只是更多信息:

类定义

class Abstract 
{ 
public: 
    virtual void something() = 0; 
}; 

class Base : public Abstract 
{ 
    int a; 
public: 
    Base() {} 
    Base(int a) : a(a){} 
    virtual void something() 
    { 
     cout << "Base" << endl; 
    } 
}; 

class Derived : public Base 
{ 
    int b; 
public: 
    Derived() {} 
    Derived(int a, int b) : Base(a), b(b){} 
    virtual void something() 
    { 
     cout << "Derived" << endl; 
    } 
}; 

简单的测试

void setBase(Container &toSet) 
{ 
    Base base(15); 
    toSet.set(base); 
} 

void setDerived(Container &toSet) 
{ 
    Derived derived(10, 30); 
    toSet.set(derived); 
} 

int main() 
{ 
    Container co; 

    Base base(15); 
    Derived derived(10, 30); 

    Base *basePtr; 
    Derived *derivedPtr; 

    //This is fine 
    co.set(base); 
    basePtr = static_cast<Base *>(co.get()); 
    basePtr->something(); 

    //This is fine 
    co.set(derived); 
    derivedPtr = static_cast<Derived *>(co.get()); 
    derivedPtr->something(); 

    //Reset 
    basePtr = nullptr; 
    derivedPtr = nullptr; 

    //Dangling pointer! 
    setBase(co); 
    basePtr = static_cast<Base *>(co.get()); 
    basePtr->something(); 

    //Dangling pointer! 
    setDerived(co); 
    derivedPtr = static_cast<Derived *>(co.get()); 
    derivedPtr->something(); 

    return 0; 
} 
+0

护理分享downvote的原因是什么? – silentwf

+2

的可能的复制[什么是智能指针,当我应该使用一个?(http://stackoverflow.com/questions/106508/what-is-a-smart-pointer-and-when-should-i-use - 酮) – LogicStuff

+0

@silentwf的downvote原因的提示,当你悬停鼠标指针的DV按钮共享。 –

回答

6

你需要做的是定义你我具体地说是血管所有权。

Container::set接受由参考基准Abstract情况下,通常并不意味着是所有权的转移:

void set(Abstract &obj){...} // Caller retains ownership of obj, but now we have a weak reference to it 

然后删除的责任不在你。

Container::get返回一个指针这意味着所有权,这表明有人谁调用set应该传递的对象不坏。

Abstract* get(){...} 

这可能是有问题的,正如你所说的。

您有几种选择

  • 编码与适当的文件(Code by contract
  • 使用智能指针像std::shared_ptr

在前一种情况下,无论是内Container这些内存所有权语义作品与否取决于用户阅读和理解你的API,然后表现得很好。在后一种情况下,指针对象拥有自己,并在最后一个实例超出作用域时删除分配的内存。

void set(std::shared_ptr<Abstract> obj){...} 
// now Container participates in the lifetime of obj, 
// and it's harder to nullify the underlying object 
// (you'd have to be intentionally misbehaving) 
+0

因为我讨厌愚蠢像'删除myContainer.get();'我可以说服你'摘要及获得(){...}'? – user4581301

+0

@ user4581301:你为什么要删除'myContainer.get()'?它会自行删除,手动调用'delete'会导致分段错误。 – AndyG

+0

是的。这是粗心的,但你可以做到。这个问题可能不会是公然直接的错误,而是错误处理后面几行代码看起来像一个原始指针的问题。这个参考文件增加了意外闯入故意行为不便的类别的难度。 – user4581301

1

如果您担心在其他地方释放对象导致悬挂指针,您可以使用boost智能指针。

提升智能指针将为您提供簿记服务并帮助避免此类情况。

的一些信息可以在这里找到: smart pointers (boost) explained

1

这是std::unique_ptr是什么:

class Container 
{ 
    std::unique_ptr<Abstract> thing; 
public: 
    void set(std::unique_ptr<Abstract> obj) 
    { 
     thing = obj; 
    } 

    Abstract* get() 
    { 
     return thing.get(); 
    } 
}; 

现在Abstract对象是“拥有”的Container,将被自动清理时Conatiner被销毁。

如果你想有可能活得更长,或者多张容器之间可以共享的指针,使用std::shared_ptr代替。

相关问题