C++ C++;在没有悬空指针的情况下将抽象类的派生对象添加到另一个类中?
我有一个简单的容器类,它指向一个抽象类,我有一些函数来获取/设置容器类中的指针。更具体地说,该类如下所示:C++ C++;在没有悬空指针的情况下将抽象类的派生对象添加到另一个类中?,c++,containers,abstract-class,dangling-pointer,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;
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;
};
类库:公共摘要
{
INTA;
公众:
Base(){}
基(inta):a(a){}
虚拟空某物
{
不能做某事;
返回0;
}
您需要做的是具体定义内存所有权
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(){...}
正如你所说的,这可能会有问题
你有几个选择
- 使用适当的文档在
容器中对这些内存所有权语义进行编码()
- 使用智能指针,如
std::shared\u ptr
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)
void集(std::shared_ptr obj){…}
//现在容器参与了obj的生命周期,
//而且很难使底层对象无效
//(你必须故意行为不端)
如果您担心对象被释放到其他地方会导致指针悬空,可以使用boost智能指针
Boost smart pointers将为您提供簿记服务,并帮助您避免此类情况
可在此处找到一些信息:
这就是
std::unique\u ptr
的作用:
class Container
{
std::unique_ptr<Abstract> thing;
public:
void set(std::unique_ptr<Abstract> obj)
{
thing = obj;
}
Abstract* get()
{
return thing.get();
}
};
类容器
{
std:独一无二的东西;
公众:
无效集(标准::唯一对象)
{
事物=对象;
}
抽象*get()
{
return thing.get();
}
};
现在,Abstract
对象由Container
拥有,当Container
被销毁时,该对象将被自动清除
如果您想要一个寿命更长的指针,或者可以在多个容器之间共享,请改用
std::shared_ptr
。是否愿意共享下一票的原因?当您用鼠标指针悬停DV按钮时,工具提示中可能会共享@silentwf下一票的原因。因为我讨厌像这样的愚蠢行为delete myContainer.get();
我能和你谈谈Abstract&get(){…}
?@user4581301:你为什么要删除myContainer.get()
?它会自动删除,手动调用delete
会导致分段错误。是的。这很粗心,但你可以做到。问题可能不是明显的即时错误,而是在几十行代码之后错误处理了看起来像原始指针的内容。该参考增加了分段的难度重新回到故意行为不端的类别。@AndyG好奇上半部分是如何解决问题的?假设没有“得到”函数,则我仍然必须使用智能指针否?如果用户表现良好,则不需要使用智能指针。契约式设计假定满足先决条件和后决条件。因此,get
的一个先决条件是,在先前的集合中添加的数据未失效。