Why is my program crashing when using multiple classes and pointers?

  • Thread starter JonnyG
  • Start date
  • Tags
    Program
In summary: L); folders.addMsg(this);}void Message::remove(Folder... folders) { folders.erase(mL); folders.remMsg(this);}void Message::addToFolders(const Message& msg) { for (auto folder : msg.folders) { folder->addMsg(this);}}void Message::removeFromFolders() { for (auto folder : folders) { folder->remMsg(this);
  • #1
JonnyG
233
30
Following my book, we are making a program with two classes: Message and Folder. The idea is that messages will be stored in a folder. The same message can be saved in multiple folders. In order to accomplish this, Message has a set of pointers to Folder that point to each of the folders that contains it. Folder has a set of pointers to Message that point to each of the messages it contains. Here is my code:

Message.hpp:
#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.cpp:
#include "Message.hpp"

Message::Message(const Message &msg) : contents(msg.contents), folders(msg.folders) {
    addToFolders(msg);
}

Message::~Message() {
    removeFromFolders();
}

Message& Message::operator=(const Message &rhs) {
    removeFromFolders();
    contents = rhs.contents;
    folders = rhs.folders;
    addToFolders(rhs);
    return *this;
}

void Message::save(Folder &f) {
    folders.insert(&f);
    f.addMsg(this);
}

void Message::remove(Folder &f) {
    folders.erase(&f);
    f.remMsg(this);
}

void Message::addToFolders(const Message &msg) {
    for (auto f : msg.folders)
        f->addMsg(this);
}

void Message::removeFromFolders() {
    for (auto f : folders)
        f->remMsg(this);
}

void Message::swap(Message &lhs, Message &rhs) {
    using std::swap;
    for (auto f : lhs.folders)
        f->remMsg(&lhs);
   
    for (auto f: rhs.folders)
        f->remMsg(&rhs);
   
    swap(lhs.folders, rhs.folders);
    swap(lhs.contents, rhs.contents);
   
    for (auto f : lhs.folders)
        f->addMsg(&lhs);
       
    for (auto f : rhs.folders)
        f->addMsg(&rhs);
}

Folder.hpp:
#ifndef FOLDER_HPP
#define FOLDER_HPP
#include <set>

using std::set;

class Message;
class Folder
{

public:
    void addMsg(Message*);
    void remMsg(Message*);
   
private:
   
    set<Message*> containedMessages;
};

#endif

Folder.cpp:
#include "Folder.hpp"

void Folder::addMsg(Message *msg) {
    containedMessages.insert(msg);
}

void Folder::remMsg(Message *msg) {
    containedMessages.erase(msg);
}

My test code that I run in my main.cpp file is (I've removed include directives and other statements for brevity):

main.cpp:
int main() {
    Message msg("testing");
    Folder inbox;
    msg.save(inbox);

}

This program crashes. Playing with the program, looking at my debugger, and using a memory checker program, it appears the problem is ultimately coming from my remMsg function in the Folder.cpp file. But I can't figure out exactly what's happening. My memory checker gives errors that say unaddressable memory and invalid heap argument, so I know it has something to do with memory getting deleted and dangling pointers, but I can't seem to fix the program.

Any tips?

Edit: I've suspected that when reaching the end of the main function, my Folder object may be getting deleted before my Message object, which leaves the set of pointers that point to my folder dangling (this set is a data member of my Message object). I would need to have access to the Message class members in my Folder destructor to account this possibility, but I cannot #include my Message header in my Folder header, because the Folder header is already #included in my Message header.
 
Last edited:
Technology news on Phys.org
  • #2
JonnyG said:
Following my book, we are making a program with two classes: Message and Folder. The idea is that messages will be stored in a folder. The same message can be saved in multiple folders. In order to accomplish this, Message has a set of pointers to Folder that point to each of the folders that contains it. Folder has a set of pointers to Message that point to each of the messages it contains. Here is my code:

Message.hpp:
#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.cpp:
#include "Message.hpp"

Message::Message(const Message &msg) : contents(msg.contents), folders(msg.folders) {
    addToFolders(msg);
}

Message::~Message() {
    removeFromFolders();
}

Message& Message::operator=(const Message &rhs) {
    removeFromFolders();
    contents = rhs.contents;
    folders = rhs.folders;
    addToFolders(rhs);
    return *this;
}

void Message::save(Folder &f) {
    folders.insert(&f);
    f.addMsg(this);
}

void Message::remove(Folder &f) {
    folders.erase(&f);
    f.remMsg(this);
}

void Message::addToFolders(const Message &msg) {
    for (auto f : msg.folders)
        f->addMsg(this);
}

void Message::removeFromFolders() {
    for (auto f : folders)
        f->remMsg(this);
}

void Message::swap(Message &lhs, Message &rhs) {
    using std::swap;
    for (auto f : lhs.folders)
        f->remMsg(&lhs);

    for (auto f: rhs.folders)
        f->remMsg(&rhs);

    swap(lhs.folders, rhs.folders);
    swap(lhs.contents, rhs.contents);

    for (auto f : lhs.folders)
        f->addMsg(&lhs);
   
    for (auto f : rhs.folders)
        f->addMsg(&rhs);
}

Folder.hpp:
#ifndef FOLDER_HPP
#define FOLDER_HPP
#include <set>

using std::set;

class Message;
class Folder
{

public:
    void addMsg(Message*);
    void remMsg(Message*);

private:

    set<Message*> containedMessages;
};

#endif

Folder.cpp:
#include "Folder.hpp"

void Folder::addMsg(Message *msg) {
    containedMessages.insert(msg);
}

void Folder::remMsg(Message *msg) {
    containedMessages.erase(msg);
}

My test code that I run in my main.cpp file is (I've removed include directives and other statements for brevity):

main.cpp:
int main() {
    Message msg("testing");
    Folder inbox;
    msg.save(inbox);

}

This program crashes. Playing with the program, looking at my debugger, and using a memory checker program, it appears the problem is ultimately coming from my remMsg function in the Folder.cpp file. But I can't figure out exactly what's happening. My memory checker gives errors that say unaddressable memory and invalid heap argument, so I know it has something to do with memory getting deleted and dangling pointers, but I can't seem to fix the program.

Any tips?
It looks like in removeFromFolders, called from msg's destructor, it dereferences a pointer to inbox (->remMsg). But when the main function exits, inbox is destroyed before msg is, so when msg's destructor is called, the pointer to inbox is an invalid pointer. You can try printing something in their destructors to see what's happening more clearly.
 
Last edited:
  • Like
Likes JonnyG
  • #3
Ah yes, your suggestion to print statements in the destructors have confirmed my suspicions. Thank you, Jarvis.

If you see my edit in my OP, I suspected this may have been the problem but I couldn't access the Message data members in the Folder class because Folder class already #included the Message class, so I couldn't #include the Message class in the Folder class.

What I did was create one header for both classes and I made Folder a friend of Message. This gave me access to the Message data members and allowed me to write this in the Folder destructor:

C++:
Folder::~Folder() {
    for (auto m : containedMessages)
        m->folders.erase(this);
}

This ensures that there will be no dangling pointers if Folder happens to be deleted first.

Now I am starting to understand what is meant by C++ makes it much harder to shoot yourself in the foot than C does, but when you do it blows off your entire leg.
 
  • Like
Likes Jarvis323
  • #4
@Jarvis323

One more question if you don't mind. I notice that I have been changing the size of my set container with range-for loops by erasing and inserting objects. I was under the impression that this was a very bad idea because it could cause a big error. Any idea why my program is working perfectly fine?
 
  • #5
JonnyG said:
@Jarvis323

One more question if you don't mind. I notice that I have been changing the size of my set container with range-for loops by erasing and inserting objects. I was under the impression that this was a very bad idea because it could cause a big error. Any idea why my program is working perfectly fine?
It looks like you're not adding or removing any objects to the container you're looping over, but just to the containers held by those objects. That should be fine.
 
  • Like
Likes JonnyG
  • #6
Makes sense. Thank you!
 

1. Why does this program keep crashing?

There could be several reasons why a program is crashing. It could be due to a bug in the code, lack of memory, incompatible hardware or software, or corrupted files. It is important to troubleshoot and identify the specific cause in order to find a solution.

2. How can I prevent this program from crashing?

To prevent a program from crashing, it is important to follow good coding practices, regularly update the software and hardware, and ensure that the program has enough memory and resources to run smoothly. Identifying and fixing any bugs or errors in the code can also help prevent crashes.

3. Is there a way to recover data from a crashed program?

In some cases, it may be possible to recover data from a crashed program. It is recommended to regularly save your work while using a program to minimize the risk of losing data. If the program has an auto-save feature, it may be possible to retrieve the last saved version of your work.

4. Can outdated software or hardware cause a program to crash?

Yes, outdated software or hardware can cause a program to crash. This is because newer programs may not be compatible with older versions of software or hardware. It is important to regularly update your software and hardware to ensure compatibility and prevent crashes.

5. What should I do if a program keeps crashing even after troubleshooting?

If a program continues to crash even after troubleshooting, it may be necessary to seek assistance from a technical expert. They may be able to identify the root cause of the issue and provide a solution. It may also be necessary to contact the program's developer for support or to report the issue.

Similar threads

  • Programming and Computer Science
Replies
3
Views
1K
  • Programming and Computer Science
Replies
23
Views
1K
  • Programming and Computer Science
Replies
4
Views
1K
  • Programming and Computer Science
3
Replies
75
Views
4K
  • Programming and Computer Science
2
Replies
36
Views
2K
  • Programming and Computer Science
3
Replies
89
Views
4K
  • Programming and Computer Science
Replies
3
Views
1K
  • Programming and Computer Science
Replies
30
Views
2K
  • Programming and Computer Science
Replies
16
Views
3K
  • Programming and Computer Science
Replies
2
Views
2K
Back
Top