我有两个四个班级:
MainClass 有一个从xml文件中读取内容的方法。 在此方法中,它首先创建 XmlReader 的实例,并为其提供xml文件作为构造函数参数。此xmlReader只需要存在于此方法中:
XmlReader xmlReader (xmlFile);
xmlReader解析xmlFile。 MainClass 通过调用 XmlReader 中的get-methods来访问xml-stuff。到目前为止一切都很好。
但是, XmlReader 提供的方法之一是根据从xml文件读取的信息创建 SerialPortSettings 类型的对象的方法:
SerialPortSettings* XmlReader::getSerialPortSettings() {
.... // reading stuff from xml file
return new SerialPortSettings(baudRate, dataBits, comport);
}
从 MainClass 调用此方法,返回值存储在指针中:
SerialPortSettings* settings = xmlReader.getSerialPortSettings();
MainClass的下一步是创建一个 SerialPortListener (这是一个必须存在的成员变量,直到退出MainClass)。 SerialPortListener在其构造函数中引用SerialPortSettings:
m_serialPortListener = new SerialPortListener(*settings);
因此,在MainClass退出之前,SerialPortSettings也必须存在,因此我将其创建为指针。
所以这是线索:
在 SerialPortListener 析构函数中,我尝试删除 SerialPortSettings - 对象:
SerialPortListener::~SerialPortListener() {
delete &m_settings;
}
然后在 MainClass 析构函数中删除了 SerialPortListener - 对象:
MainClass::~MainClass() {
delete m_serialPortListener;
}
这失败了。我收到一个错误,说我在主类中删除了两次:
*** glibc detected *** ./ioserver: double free or corruption (out): 0x00860d80 ***
当我从SerialPortListener中删除delete& m_settings时,它可以正常工作。 但什么时候应该删除指针?什么是正确的做法?我真的希望我的xml-reader创建SerialPortSettings - 对象,将所有信息(波特率,comport等)返回给MainClass并自己创建SerialPortSettings对象。
答案 0 :(得分:1)
一个好的解决方案就是让xmlReader::getSerialPortSettings
按值返回SerialPortSettings
。
让编译器进行优化。
但是,如果您需要处理指针生存期,请使用智能指针,例如std::auto_ptr
或boost::shared_ptr
。关键的想法是定义所有权。所有者(在boost::shared_ptr
的情况下是引用该对象的智能指针的集合)负责删除 - 没有其他人。
干杯&第h。,
答案 1 :(得分:0)
指针应该在MainClass的末尾删除。
答案 2 :(得分:0)
对参考文献使用delete
毫无意义(至少对我而言)。
没有XML阅读器创建新对象会更清晰;将SerialPortSettings视为“哑”容器,只需传入一个引用来填充XML中的数据:
XmlReader::getSerialPortSettings(SerialPortSettings& settings);
实际的实例可以是主程序中的局部变量,并在创建时传递(通过const引用,这次)到串口:
SerialPortSettings portSettings;
m_xmlReader->getSerialPortSettings(portSettings);
m_serialPort = new SerialPort(portSettings);
设置实例的生命周期自然与它所在的范围相同,因为它只是一个局部变量。
如果读取XML的主类中的方法需要在串行端口超出范围之前退出,则可以将设置设置为主类的成员变量。
答案 3 :(得分:0)
m_settings的数据类型是什么?它是SerialPortSettings *还是SerialPortSettings?如果是后者,无论如何都不能删除它,因为它是在堆栈上分配的。如果它是前者(指针),则不需要引用运算符。只需写下delete m_settings;
答案 4 :(得分:0)
删除中的简单拼写错误:
delete &m_settings;
应该是:
delete m_settings;
对于任何指针,你应该决定谁owns
指针,那应该是谁删除它。
或者您可以使用shared_ptr
之类的智能指针并完全消除问题。
答案 5 :(得分:0)
SerialPortListener::~SerialPortListener() {
delete &m_settings;
}
那块看起来很奇怪。您确定不是要通过引用删除值吗?原因C ++在您删除类时会自动执行,因此您的删除实际上是在尝试删除两次。
答案 6 :(得分:0)
好的,首先,你错过了真正重要的信息,即如何存储SerialPortListener :: m_settings。由于你得到的错误,我猜你实际上是在存储它的副本,这意味着:我打赌你有类似的东西:
class SerialPortListener {
SerialPortSettings m_settings;
SerialPortListener(SerialPortSettings set) {
m_settings = set;
}
}
如果它与此类似,那么监听器将对象的副本保存在它自己的内存中,并且删除它没有意义,因为它不是指针。经验法则,除非你知道自己在做什么并意识到自己真的需要,否则永远不要删除任何东西。
就“正确性”而言,指针应由主类释放,因为它是由谁创建的。或者,如果您在主类中没有任何用处,并希望侦听器删除它,请在侦听器中保存指针而不是对象或引用。
答案 7 :(得分:0)
我最终将m_serialPortSettings作为SerialPortListener中的指针,并从那里删除它。