有关删除指针的问题。应从哪个类中删除?

时间:2011-01-25 12:59:43

标签: c++ pointers

我有两个四个班级:

  • MainClass (事情开始的课程)
  • XmlReader (用于解析xml文件的类)
  • SerialPortSettings (保存有关从xml文件读取的串口信息,例如波特率,comport等)
  • SerialPortListener (在其构造函数中引用SerialPortSettings对象)

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对象。

8 个答案:

答案 0 :(得分:1)

一个好的解决方案就是让xmlReader::getSerialPortSettings按值返回SerialPortSettings

让编译器进行优化。

但是,如果您需要处理指针生存期,请使用智能指针,例如std::auto_ptrboost::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中的指针,并从那里删除它。