c++arrayspointerscopydouble-pointer

Use Double Pointers to access values instead of doubles


My question might be a bit confusing because I really did not know how to word it. Essentially, I have three classes in total and two of them are holding double pointers of a type defined in the third class.

class Wheel
{
    unsigned m_orderID{};
    std::string m_name{};
};

The other two classes - Car & Truck - have identical private members:

class Car{
    const Wheel** m_ptrToArray{};
    size_t m_count{};
};

My problem is that, in main(), I am making changes to the Wheel class values, where the Truck needs to have values that change, but the Car class needs to remain unchanged. Because the Car and Truck are both using double pointers, any update to the Wheel values changes the output for both because they are accessing the information via address, if I'm understanding correctly.

I believe my problem lies in the constructor used to create a Car object:

Car::Car(const Wheel* wheels[], size_t count)

I am trying to make a copy of the Wheel array that's passed in, so that I can assign the copy to the Wheel** m_ptrToArray member. That way, if I update the original array in main(), only Truck will change and Car will remain untouched. But I can't figure out how to do it.

If I use the following code in my constructor:

m_ptrToArray = new const Wheel*[m_count];
for (auto i = 0u; i < m_count; i++)
{
    m_ptrToArray[i] = wheels[i];
}

It doesn't do what I want, because I'm just assigning the address of the wheels array.

If I do:

Wheel* temp = new Wheel[m_count];
for (auto i = 0u; i < m_count; i++)
{
    temp[i] = *wheels[i];
}
m_ptrToArray = new const Wheel*[m_count];
for (auto i = 0u; i < m_count; i++)
{
    m_ptrToArray[i] = &temp[i];
}

It works correctly, changing Truck but not Car. However, I run into memory loss because I'm using the new keyword without delete - because I have no idea how to pass it other than &temp[i] which means if I delete it, it won't be able to reach the value any more.

I am at a loss. Hopefully, this explanation makes sense to somebody who knows what they are doing. Let me know if you need any more information at all!


Solution

  • You are on the right track. Truck can just save the Wheel* pointers it is given, while Car can make its own copy of the Wheel objects. Simply destroy those copies in Car's destructor. That seems to be the piece you are missing. Simply store the extra objects as an additional member of the Car class, instead of using a local variable in the constructor.

    Try something like the following (FYI, I'm ignoring the need for copy/move constructors and assignment operators, per the Rule of 3/5/0. I'll leave that as an exercise for you to implement).

    For Car:

    class Car{
        const Wheel** m_ptrToArray{};
        size_t m_count{};
        Wheel* m_wheels{};
    
    public:
        Car(const Wheel* wheels[], size_t count);
        ~Car();
    };
    
    ...
    
    Car::Car(const Wheel* wheels[], size_t count)
    {
        m_count = count;
        m_wheels = new Wheel[count];
        m_ptrToArray = new const Wheel*[count];
        for (auto i = 0u; i < count; ++i)
        {
            m_wheels[i] = *(wheels[i]);
            m_ptrToArray[i] = &m_wheels[i];
        }
    }
    
    Car::~Car()
    {
        delete[] m_ptrToArray;
        delete[] m_wheels;
    }
    

    Or simpler:

    class Car{
        const Wheel** m_ptrToArray{};
        size_t m_count{};
    
    public:
        Car(const Wheel* wheels[], size_t count);
        ~Car();
    };
    
    ...
    
    Car::Car(const Wheel* wheels[], size_t count)
    {
        m_count = count;
        m_ptrToArray = new const Wheel*[count];
        for (auto i = 0u; i < count; ++i)
        {
            m_ptrToArray[i] = new Wheel(*(wheels[i]));
        }
    }
    
    Car::~Car()
    {
        for (auto i = 0u; i < m_count; ++i)
        {
            delete m_ptrToArray[i];
        }
        delete[] m_ptrToArray;
    }
    

    And for Truck:

    class Truck{
        const Wheel** m_ptrToArray{};
        size_t m_count{};
    
    public:
        Truck(const Wheel* wheels[], size_t count);
        ~Truck();
    };
    
    ...
    
    Truck::Truck(const Wheel* wheels[], size_t count)
    {
        m_count = count;
        m_ptrToArray = new const Wheel*[count];
        for (auto i = 0u; i < count; ++i)
        {
            m_ptrToArray[i] = wheels[i];
        }
    }
    
    Truck::~Truck()
    {
        delete[] m_ptrToArray;
    }