-1

I'm trying to learn some OOP practices while developing a model for my research. I seem to be running into a few problems that I'm not really sure fall into the scope of the book I'm using, the C++ Primer by Stephen Prata.

Right now, I'm trying to develop an object called a StochasticModel. This SM object should be able to accept another object called a LengthDistribution and run a simulation on it. I'm currently setting up the framework for this type of interaction with the following pseudo code. As a caveat, I combined the class definitions as I originally had them in two files each. You'll also see some CudaMallocManaged() in there as I intend to use these objects on the GPU as well, but CUDA isn't the issue here.

int main()
{

//Read initial conditions, maxlength, maxiterations from input

//Create a length distribution object from IC's and length
LengthDistribution* LD = new LengthDistribution(initialconditions, maxlength)

//Create a model object to operate on LD maxiterations number of times.
StochasticModel* SM = new StochasticModel(LD, maxiterations)

//Test that I've created an LD object as I expected by printing its values out.
LD -> h_printToScreen(); //<- Works fine!

//Test that model has a correct version of LD by printing LD's information to screen through 
//SM's print to screen function.
SM->printToScreen(); //<- But when I have an object that contains the object call a function that calls its function (inception), memory access violations occur.

}

My Length Distribution class.

class LengthDistribution : public Managed
{
private:
    int m_maxlength;
    int* m_lengthDistribution;

public:
    //User defined constructor.
    LengthDistribution(int* initialconditions, int maxlength)
    {
    m_maxlength = maxlength;
    m_lengthDistribution = new int[maxlength];
    m_lengthDistribution = initialconditions; 
    }

    //Default constructor
    //Default destructor
    //Unified memory copy constructor allows pass-by-value
    LengthDistribution::LengthDistribution(const LengthDistribution &LD)
    {
    //Copy maxlength to new state.
    m_maxlength = LD.m_maxlength;

    //Allocate CUDA Managed memory for lengthDistribution array
    cudaMallocManaged(&m_lengthDistribution, m_maxlength);

    //Copy array to new state.
    memcpy(m_lengthDistribution, LD.m_lengthDistribution, m_maxlength);

    }
    __host__ void h_printToScreen()
    {
        printf("Host maxlength: ");
        std::cout<<m_maxlength; 
        std::cout<<"\n";
        printf("Host length distribution: ");
        for (int i = 0; i < m_maxlength; i++)
            std::cout<<m_lengthDistribution[i];
        printf("\n");
    }

}

My Stochastic Model class

class StochasticModel : public Managed
{

private : 
    int m_numberOfIterations;
    LengthDistribution* state;

public:
    //User defined constructor
    StochasticModel(LengthDistribution* LD, int numberOfIterations)
    {
        //Copy desired number of iterations.
        m_numberOfIterations = numberOfIterations;

        //Assign LD to SM's state variable.  I think I'm having an issue here.
        //Copy LD into SM object's state variable.
        LengthDistribution* state = new LengthDistribution(*LD);
    }

    //User defined copy constructor
    Stochastic::Model(const StochasticModel &SM)
    {   
        m_numberOfIterations = SM.m_numberOfIterations;
        cudaMallocManaged(&state, sizeof(SM.state));
        state = new LengthDistribution(*SM.state);
        //memcpy(state, SM.state, sizeof(state));
    }

    //Print out member length distribution's values.
    printToScreen()
    {
    state->h_printToScreen();  //When I trace the debugger through here, it triggers an access violation when trying to print out the state's array.
    }
}

This is that Managed class that the two other classes inherit from. Its purpose is to allow for porting to the graphics card in the future.

class Managed {
public:
  void *operator new(size_t len) {
    void *ptr;
    cudaMallocManaged(&ptr, len);
    return ptr;
  }

  void operator delete(void *ptr) {
    cudaFree(ptr);
  }
};

The end results is that the application, after being run, "has stopped working". It compiles fine, but when it hits the memory access error for the state<-printToScreen call, it "stops working." Going through the debugger, it says that the array that it's trying to print from for the LD object and the integer are not defined. I feel like I'm missing something elementary here, but I'd like to be able to use the SM object to manipulate and display information from the LD object.

  • And what's your actual compiler error message/runtime exception. I can't get a clue from your question, so how should we help? (all of that _"blah blah"_ what the code's supposed to do, doesn't help to diagnose your actual problem) – πάντα ῥεῖ Nov 13 '14 at 23:27
  • There are very very few situations where you want to actually overload the `new` and `delete` operators … Are you sure that's what you want to do? – Rufflewind Nov 13 '14 at 23:29
  • The overloading of the new and delete operators is in preparation for using Cuda Unified Memory, so sadly, I think I need it in there. If it's really a problem, then I might be able to remove it and make a purely CPU based model. – Hair of Slytherin Nov 13 '14 at 23:31

1 Answers1

2

In your constructor you've created a new local variable that hides the member variable state. That leaves the member variable undefined, causing a crash later when you try to access it.

You should prefer to use an initializer list instead:

StochasticModel(LengthDistribution* LD, int numberOfIterations) :
    m_numberOfIterations(numberOfIterations),
    state(new LengthDistribution(*LD))
{
}
Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
  • 1
    Oh, ok. I can see that now. Let me try that fix. – Hair of Slytherin Nov 13 '14 at 23:35
  • Awesome, thank you, that was a very clear explanation. I think I was confused because I thought that anytime I operated on a member variable in a class method, it was smart enough to operate on that object's stored version of the member variable. However, it seems to me that had I done "state = new LengthDistribution(*LD))" and left out the type, I might have not created a new local version of the member variable and instead operated on the desired version. Am I understanding that right? – Hair of Slytherin Nov 13 '14 at 23:55
  • 1
    @KarstenChu, yes that's exactly right. But it's an easy mistake to make, since it's just habit to declare a variable when you initialize it. By using the initializer there's no way you can have that problem. – Mark Ransom Nov 14 '14 at 00:11