-1

I've been getting this error when I run

0 [main] test 449 cygwin_exception::open_stackdumpfile: Dumping stack trace to test.exe.stackdump

I'm relatively new to c++ programming, I came from python, I'll link the code but could anyone tell me what's going on and what the issue could be?

#include <string>

#include <iostream>
using namespace std;

struct grade
{
    int totalCourses;
    string mNumber;
    string *courses = new string[totalCourses];

    grade(int numOfCourses = 10)
    {
        totalCourses = numOfCourses;
    }
    
    ~grade()
    {
        delete[] courses;
    }
};

int main()
{
    int totalGrades;
    cout << "Enter num of grades: ";
    cin >> totalGrades;
    grade *gradeArray = new grade[12];
    grade newGrade(6);
    newGrade.mNumber = "M12345678";
    cout << newGrade.mNumber << '\n';
    gradeArray[0] = newGrade;
    delete[] gradeArray;
    return 0;
}
JaMiT
  • 14,422
  • 4
  • 15
  • 31
  • 1
    Also, any particular reason to use arrays instead of the more standard vectors? – kesarling He-Him Sep 25 '20 at 03:29
  • 1
    This is where the problem seems to be: `string *courses = new string[totalCourses];` – kesarling He-Him Sep 25 '20 at 03:38
  • 1
    `gradeArray[0] = newGrade;` Another problem. Your `grade` class does not properly adhere to the [rule of three](https://stackoverflow.com/questions/4172722/what-is-the-rule-of-three). You are assigning `grade` objects, and `grade` has incorrect copy semantics. – PaulMcKenzie Sep 25 '20 at 03:39
  • Well, at some point the OP has to implement the copy semantics correctly. Maybe by doing so, they will fix all the other bugs. Or just use `std::vector` and let it do the work. – PaulMcKenzie Sep 25 '20 at 04:00
  • *I came from python* -- `string *courses = new string[totalCourses];` -- Note that any user-based C++ code that does this is now considered a code smell. Unless you're implementing your own data structure or something highly specialized, it is no longer necessary to write code this way (creating dynamic arrays using `new[]`). Code like that has been superseded by using `std::vector`. – PaulMcKenzie Sep 25 '20 at 04:03
  • 1
    *Debugging tip of the day:* Create a [mre]. Remove lines until you have the fewest that demonstrate your issue. It looks like you tried a few tests of your `grade` object; which one is causing the crash? Can you eliminate assigning one grade to another? Eliminate reading and setting the `mNumber` field? Eliminate creating (and deleting) an array of grade objects? What is the bare minimum you need for a crash, and on what line does the crash occur? – JaMiT Sep 25 '20 at 04:06
  • `string *courses = new string[totalCourses];` what is the value of `totalCourses` at this moment?? – David C. Rankin Sep 25 '20 at 04:32
  • The reason I can't use vector is because of the class I'm in. Believe me I wish I could. I've found that when I comment out the delete[] gradeArray, I no longer get the error. – Jaron Ritter Sep 25 '20 at 04:57
  • @JaronRitter *I've found that when I comment out the delete[] gradeArray, I no longer get the error* -- All you did was create a memory leak, and did not fix the error. The fault is not the `delete[]` -- you should put it back in the code and actually fix the issue. – PaulMcKenzie Sep 25 '20 at 18:52
  • @PaulMcKenzie Yes I'm aware that creates a memory leak. I thought it might give someone insight as to what could be going wrong – Jaron Ritter Sep 26 '20 at 19:07
  • The insight is two-fold -- you are using an uninitialized variable when using `new[]`, and you failed to implement the correct copy semantics for your `grade` class, thus copying (as you're doing later on) will cause undefined behavior. The latter should have been mentioned in the class you're taking if the teacher insists you do things this way -- otherwise you would have never known this missing piece of the puzzle. – PaulMcKenzie Sep 26 '20 at 19:11

1 Answers1

0

This question is a bit tricky to answer because there are two sources of undefined behavior. Either one could cause a crash, but at the same time, either one could seem to work as intended. Some find it surprising, but that is how undefined behavior works in C++; it's not "any behavior other than the intended is allowed", but simply "any behavior is allowed".

Problem 1

Class members are initialized before the opening brace of a constructor's body. Here is an annotated version of your constructor.

    grade(int numOfCourses = 10)   // Constructor starts
    // Members `totalCourses`, `mNumber`, and `courses` are initialized here. However,
    // you specified an initial value only for `courses`, so effectively you initialize:
    // courses = new string[/* unspecified value */];
    {
        // It is only here, *after* the opening brace, that `totalCourses` gets a value.
        totalCourses = numOfCourses;
    }

You must be consistent in how you initialize these related fields. If one depends on a parameter, then both depend on a parameter. Use an initialization list to accomplish this.

    grade(int numOfCourses = 10) :
        totalCourses(numOfCourses),
        courses(new string[numOfCourses]) // Use the parameter for robustness (the order
    {}                                    // of fields here is not always the order in
                                          // which the fields are initialized).

Problem 2

You have defined a (non-trivial) destructor but have not followed the Rule of Three. Follow the link for details on why you need to define a copy constructor and copy assignment operator. (If this was the only problem, this question would have remained closed as a duplicate.)

JaMiT
  • 14,422
  • 4
  • 15
  • 31