Search code examples
c++pointersinheritanceabstract-class

Taking a pointer to a derived class ends in a runtime exception in C++


I have a simple abstract base class:

class Sensor {
protected:
    GenericDriver *driver;
public:
    Sensor() {};
    virtual void startNewReadout(void) = 0;
};

From which I derive a concrete class:

class OneWireSensor : public Sensor {
private:
    OneWireDriver oneWireDriver; //not really necessary here
public:
    OneWireSensor(PinData *pinData);
    void startNewReadout(void){
        this->driver->driverStartReadout();
    }
};

Now, when I use the below constructor, my code compiles and runs just as expected:

OneWireSensor::OneWireSensor(PinData *pinData) : oneWireDriver(OneWireDriver(pinData)) {
    this->driver = &oneWireDriver;
}

However, the field oneWireDriver is not used anywhere in my code and I don't want to set it. But when I remove it from the OneWireSensor class and use a constructor as follows:

OneWireSensor::OneWireSensor(PinData *pinData) {
    OneWireDriver oneWireDriver(pinData);
    this->driver = &oneWireDriver;
}

The code compiles fine but the execution ends in a runtime exception (a system hard fault since I am on embedded). GenericDriver is an abstract class from which OneWireDriver class inherits. What am I doing wrong in the second case?


Solution

  • The problem is most likely caused by the dangling pointer from the constructor of OneWireSensor.

    OneWireSensor::OneWireSensor(PinData *pinData) {
    
        // A function local object.
        OneWireDriver oneWireDriver(pinData);
    
        // Pointer to the function local object.
        // It becomes a dangline pointer as soon as the function returns.
        this->driver = &oneWireDriver;
    }
    

    You need to use a dynamically allocated object.

    OneWireSensor::OneWireSensor(PinData *pinData) {
    
        this->driver = new OneWireDriver(pinData);
    }
    

    But then you'll have to write code to manage the dynamically allocated memory. It'll be better to use a smart pointer instead of a raw pointer. See https://en.cppreference.com/w/cpp/memory for more on smart pointers.