sil*_*twf 0 c++ containers abstract-class dangling-pointer
我有一个简单的容器类,指向一个抽象类,我有函数来获取/设置容器类中的指针.更具体地说,这个类看起来像这样:
class Container
{
Abstract* thing;
public:
void set(Abstract &obj)
{
thing = &obj; //danger of dangling pointer
}
Abstract* get()
{
return thing;
}
};
Run Code Online (Sandbox Code Playgroud)
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;
}
};
Run Code Online (Sandbox Code Playgroud)
简单的测试
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;
}
Run Code Online (Sandbox Code Playgroud)
您需要做的是具体地定义您的内存所有权.
Container::set接受Abstract引用的实例,这通常不意味着所有权转移:
void set(Abstract &obj){...} // Caller retains ownership of obj, but now we have a weak reference to it
Run Code Online (Sandbox Code Playgroud)
然后删除的责任不在你身上.
Container::get返回一个暗示所有权的指针,表示调用的人set不应使传递的对象无效.
Abstract* get(){...}
Run Code Online (Sandbox Code Playgroud)
正如您所说,这可能会有问题.
你有几个选择
在前一种情况下,它是否有效取决于用户阅读和理解您的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)
Run Code Online (Sandbox Code Playgroud)