Search code examples
c++destructor

Destructor called when I return new instance of object in if-statement


class Vec
{
public:
    unsigned int dim;
    float* elements;

    // Constructors
    Vec() : dim(0), elements(nullptr) {}

    Vec(unsigned int dim, ...) : dim(dim), elements(new float[dim])
    {
        va_list args;
        va_start(args, dim);

        for (unsigned int i = 0; i < dim; i++)
        {
            // C/C++ promotes floats passed as variable arguments to double,
            // so you need to use va_arg(args, double) and cast it to float
            elements[i] = static_cast<float>(va_arg(args, double));
        }

        va_end(args);
    }

    Vec(unsigned int dim, float value) : dim(dim), elements(new float[dim])
    {
        for (unsigned int i = 0; i < dim; i++)
        {
            elements[i] = value;
        }
    }

    // Destructor
    ~Vec()
    {
        delete[] elements;
    }
};


Vec vecAdd(Vec* v1, Vec* v2)
{
    if (v1->dim != v2->dim)
    {
        //Vec VEC_UNDEFINED;
        //return VEC_UNDEFINED;
        return Vec;
    }

    Vec ret(v1->dim);

    for (unsigned int i = 0; i < ret.dim; i++)
    {
        ret.elements[i] = v1->elements[i] + v2->elements[i];
    }

    return ret;
}

If I call the class and add to vectors together and return the ret object the destructor is called and all ret.elements get deleted which I don't want.

If I would commant out the "return Vec;" in my boundary check and uncommant the "//Vec VEC_UNDEFINED; //return VEC_UNDEFINED;" the destructor would not be called and the code works as expected. Why does C++ behave like this?


Solution

  • You can improve your code using templates (assuming your vector dimension is fixed which seems to make sense based on your code) it would look something like this (otherwise just use std::vector or wrap that)

    #include <array>
    #include <algorithm>
    #include <iostream>
    
    template<std::size_t dim_v>
    class Vec final
    {
    public:
        explicit Vec(const float(&values)[dim_v]) 
        {
            std::copy(std::begin(values),std::end(values),m_values.begin());
        }
    
        explicit Vec(float value)
        {
            std::fill(m_values.begin(), m_values.end(), value);
        }
    
        // Destructor
        ~Vec() = default;
    
        const auto& values() const noexcept
        {
            return m_values;
        }
    
        constexpr auto& dims() const noexcept
        {
            return dim_v;
        }
    
    private:
        std::array<float, dim_v> m_values;
    };
    
    int main()
    {
        Vec v{ {0.f,1.f,2.f} };
    
        for (const auto& value : v.values())
        {
            std::cout << value << "\n";
        }
    }