My destructor is causing my program to crash

  • Context:
  • Thread starter Thread starter JonnyG
  • Start date Start date
  • Tags Tags
    Crash Program
Click For Summary

Discussion Overview

The discussion revolves around a programming issue related to the implementation of a class using a raw pointer in C++. Participants explore the problems arising from the destructor and copy constructor of a class named HasPtr, particularly in the context of using a vector to store instances of this class. The focus is on memory management and the implications of using raw pointers versus smart pointers.

Discussion Character

  • Technical explanation
  • Debate/contested

Main Points Raised

  • One participant identifies a clear issue in the copy constructor that may lead to the program crash, suggesting that the destructor is causing problems due to dangling pointers.
  • Another participant confirms the issue with the copy constructor and suggests a modification to create a new string instead of copying the pointer directly.
  • A different approach is proposed, advocating for the use of smart pointers to avoid mismatched new/delete issues, along with an example of how to implement HasPtr using std::unique_ptr.
  • There is also a suggestion to simplify the design by using a std::string directly instead of a pointer to a std::string.

Areas of Agreement / Disagreement

Participants generally agree that there are issues with the current implementation of the copy constructor and destructor. However, there are differing opinions on the best approach to resolve these issues, with some advocating for smart pointers and others suggesting modifications to the existing code.

Contextual Notes

The discussion highlights limitations related to memory management when using raw pointers, as well as the potential for memory leaks and crashes if not handled correctly. The requirement to use a built-in pointer in the exercise adds complexity to the problem.

JonnyG
Messages
233
Reaction score
45
Below is my code. The include directives and the using std::* declarations have been removed for brevity:

C++:
class HasPtr {
    friend void swap(HasPtr&, HasPtr&);
public:
    HasPtr(const std::string &s = string()): ps(new string(s)), i(0) {}
    HasPtr(const string &s, const int &j) : ps(new string(s)), i(j) {}
    HasPtr(const int &j) : ps(new string()), i(j) {}
    HasPtr(const HasPtr &hp) : ps(hp.ps), i(hp.i) {} //copy constructor
   
    //copy-assignment operator
    HasPtr& operator=(HasPtr rhs) {
        swap(*this, rhs);
        return *this;
    }

    bool operator<(const HasPtr &rhs) {
        return this->i < rhs.i;
    }  

    //destructor
    ~HasPtr() {
        delete ps;
    }
       
    std::string *ps;
    int i;
};

inline void swap(HasPtr &hp1, HasPtr &hp2) {
    using std::swap;
    swap(hp1.ps, hp2.ps);
    swap(hp1.i, hp2.i);
}

int main() {
    HasPtr p1(32), p2(44);
    vector<HasPtr> v {p1, p2};
}

Whenever I run this program, it crashes. I ran my debugger and I also ran a memory-checking program on the compiled executable and it looks as if my HasPtr destructor is causing problems. It appears to me that when I initialize my vector, it makes a local copy of p1 and p2 and when the initializing is done, it runs my destructor on these local copies of p1 and p2, resulting in the other p1 and p2 objects (the original ones in the main scope) containing dangling pointers and thus crashing the program.

My destructor must delete the memory pointed to by the object, because otherwise once my object is deleted, the pointer will be deleted but the actual memory itself won't be freed, so I will have a memory leak.

Given this, how can I create a vector of HasPtr objects? Every method for putting HasPtr objects into the vector results in temporaries being created, which seems to be what is causing the problem in the first place.

EDIT: This class is the result of the exercises in my book, and it is required that I use a built-in pointer in this exercise, so I cannot use a smart pointer to replace the built-in pointer.
 
Technology news on Phys.org
There is a clear issue in your copy constructor which, when used, will lead to the bug you see.
 
  • Like
Likes   Reactions: jbunniii and JonnyG
Filip Larsen said:
There is a clear issue in your copy constructor which, when used, will lead to the bug you see.

I literally just came into this thread to make an update that I figured it out. I changed,

ps(hp.ps)

to

ps(new string(*hp.ps))
 
  • Like
Likes   Reactions: Filip Larsen
Using smart pointers avoids problems with mismatched new/delete.
C++:
#include <memory>
#include <string>
#include <vector>

class HasPtr {
    friend void swap(HasPtr&, HasPtr&);
public:
    HasPtr(const std::string &s = std::string()): ps(std::make_unique<std::string>(s)), i(0) {}
    HasPtr(const std::string &s, const int &j) : ps(std::make_unique<std::string>(s)), i(j) {}
    HasPtr(const int &j) : ps(std::make_unique<std::string>()), i(j) {}
    //copy constructor
    HasPtr(const HasPtr &hp)
    : i(hp.i)
    {
        if (hp.ps != nullptr) {
            ps = std::make_unique<std::string>(*hp.ps);
        }
    }

    //copy-assignment operator and operator< unchanged from raw pointer implementation:
    HasPtr& operator=(HasPtr rhs) {
        swap(*this, rhs);
        return *this;
    }

    bool operator<(const HasPtr &rhs) {
        return this->i < rhs.i;
    }

    //destructor
    ~HasPtr() {
        // nothing to do, unique_ptr destroys the object it points to
    }

    std::unique_ptr<std::string> ps;
    int i;
};
Or just avoid the whole mess by making the member variable a std::string instead of a pointer to a std::string.
 

Similar threads

Replies
5
Views
2K
Replies
89
Views
6K
  • · Replies 19 ·
Replies
19
Views
2K
Replies
5
Views
2K
  • · Replies 5 ·
Replies
5
Views
3K
  • · Replies 89 ·
3
Replies
89
Views
6K
  • · Replies 3 ·
Replies
3
Views
2K
Replies
7
Views
4K
  • · Replies 118 ·
4
Replies
118
Views
10K
Replies
10
Views
2K