C++ 悬空指针(我认为)导致程序崩溃?
在我的书(C++Primer第5版)之后,我们正在制作一个包含两个类的程序:消息和文件夹。想法是一条消息将存储在文件夹中。相同的消息可以保存在多个文件夹中。为了实现这一点,消息有一组指向文件夹的指针,指向包含它的每个文件夹文件夹有一组指向消息的指针,这些指针指向它包含的每个消息。这是我的密码: Message.hpp:C++ 悬空指针(我认为)导致程序崩溃?,c++,C++,在我的书(C++Primer第5版)之后,我们正在制作一个包含两个类的程序:消息和文件夹。想法是一条消息将存储在文件夹中。相同的消息可以保存在多个文件夹中。为了实现这一点,消息有一组指向文件夹的指针,指向包含它的每个文件夹文件夹有一组指向消息的指针,这些指针指向它包含的每个消息。这是我的密码: Message.hpp: #ifndef MESSAGE_HPP #define MESSAGE_HPP #include <string> #include <set>
#ifndef MESSAGE_HPP
#define MESSAGE_HPP
#include <string>
#include <set>
#include "Folder.hpp"
using std::string;
using std::set;
class Message
{
friend class Folder;
public:
explicit Message(const string &str) : contents(str) {}
Message(const Message&);
Message& operator=(const Message&);
~Message();
void save(Folder&);
void remove(Folder&);
private:
string contents;
set<Folder*> folders;
void addToFolders(const Message&);
void removeFromFolders();
void swap(Message&, Message&);
};
#endif // MESSAGE_HPP
Folder.hpp:
#ifndef FOLDER_HPP
#define FOLDER_HPP
#include <set>
#include <string>
using std::string;
using std::set;
class Message;
class Folder
{
public:
Folder(const string &str = "") : name(str) {}
void addMsg(Message*);
void remMsg(Message*);
private:
string name;
set<Message*> containedMessages;
};
#endif // FOLDER_HPP
我在main.cpp文件中使用以下代码测试程序:
int main() {
Message msg("testing");
Folder inbox;
msg.save(inbox);
}
这个程序崩溃了。使用该程序,查看我的调试器,并使用内存检查器程序,问题似乎最终来自Folder.cpp文件中的remMsg函数。但我不知道到底发生了什么。我的内存检查器给出的错误是无法寻址内存和无效堆参数,因此我知道这与内存被删除和指针悬空有关,但我似乎无法修复程序
我怀疑当到达主函数的末尾时,我的文件夹对象可能在我的消息对象之前被删除,这使得指向我文件夹的指针组悬空(这组指针是我的消息对象的数据成员)。我需要访问我的文件夹中的邮件类成员析构函数才能考虑这种可能性,但我不能将我的邮件标题包含在我的文件夹标题中,因为文件夹标题已经包含在我的邮件标题中
有什么提示吗?我的怀疑是对的。我使用print语句显示文件夹对象在Message对象之前被删除,导致指针悬空。我将两个类合并到一个标题中,以便Folder类可以访问Message类,并将其放入文件夹析构函数中:
Folder::~Folder() {
for (auto m : containedMessages)
m->folders.erase(this);
}
你说得对。主作用域尝试释放在那里创建的文件夹,然后释放作为指向该文件夹的指针接收该文件夹的集合。它正在取得它的所有权。 您可以在主文件夹中使用Folder*inbox=newfolder();然后是msg.save(*收件箱);(最丑陋的方法)或使用引用代替指针或std::shared_ptr()等 请不要使用新的,它只会绕过问题,为以后制造更多的问题,嘎嘎!。这不是个好习惯
如果您很想在使用原始指针的地方使用std::shared_ptr。在以这种方式对std::set进行迭代时,不能从
std::set
中删除(),它会使迭代器无效。看,这其实不是问题所在。我的文件夹对象在我的邮件对象之前被删除,导致指针悬空。我解决了这个问题。但是在看到您的评论之后,我记得如果我使用循环的范围对容器进行迭代,我不应该更改容器的大小。在这种情况下,为什么我的循环范围不会产生错误?更一般地说,让一个类的实例存储一个指向类外变量的指针或引用会导致未定义的行为。特别是在这种情况下,指针指向一个自动存储持续时间的变量,因此没有什么可以阻止指针超过其指针对象的寿命。此外,对于自动存储持续时间的变量,该标准要求当它们超出范围时,销毁顺序与构造顺序相反,并且在另一个对象中存储指向一个对象的指针不会影响这一点。
int main() {
Message msg("testing");
Folder inbox;
msg.save(inbox);
}
Folder::~Folder() {
for (auto m : containedMessages)
m->folders.erase(this);
}