C++ Access Violation – How to Fix Access Violation using a Basic_Point Class Template

access-violationarraysc++templates

seeking to create own point type wrote this:

so first of all using concept to constraint the type

//concept
template<typename T>
concept Numeric = requires(T param)
{
    requires std::is_integral_v<T> || std::is_floating_point_v<T>;
    requires !std::is_same_v<bool, T>;
    requires std::is_arithmetic_v<decltype(param +1)>;
    requires !std::is_pointer_v<T>;
};

the basic point template, just a wrapper arround an array

// Point<T,n>
template <Numeric T, size_t dim = 2 > 
struct basic_point {
    constexpr auto inline copy( basic_point<T,dim> const& p) {
        std::copy(p, p + dim * sizeof(p[0]), array.begin()); 
    }
    auto inline copy( T const (&p)[dim]) { 
        std::copy(p, p + dim * sizeof(p[0]), array.begin()); 
    }
    auto inline copy( T const& val) noexcept { 
        for (auto& a : array) 
            a = val; 
    }
    // new constructor
    constexpr basic_point( T const (&pt)[dim])           { copy(pt); }
    // copy constructor
    constexpr basic_point( basic_point<T,dim> const& p)  { copy(p);  }
    // default constructor
    constexpr basic_point( T dt = 0 ) noexcept           { copy(dt); }
    virtual  ~basic_point()         = default ;
 
    constexpr auto inline operator+=( basic_point<T,dim> const& o ) noexcept { 
        for(size_t i = 0; i < dim;i++) 
            array[i] += o.array[i]; 
        }
    constexpr auto inline operator-=( basic_point<T,dim> const& o ) noexcept { for(size_t i = 0; i < dim;i++) array[i] -= o.array[i]; }
    friend constexpr inline auto operator+( basic_point<T,dim> const& a, basic_point<T,dim> const& b ) noexcept { basic_point<T,dim> sum{a};  sum  += b; return sum; }
    friend constexpr inline auto operator-( basic_point<T,dim> const& a, basic_point<T,dim> const& b ) noexcept { basic_point<T,dim> rest{a}; rest -= b; return rest;}
    std::array<T,dim> array;
};

A special template then is explicitly managing a 2d point where x and y refer to elements 0 and 1 of the array, using composition, no inheritance.

//Point2D<T> 
template<Numeric T = size_t> struct Point2D {
        constexpr Point2D(T const (&p)[2])  {
            data = p;
            x = data.array[0];
            y = data.array[1];
         }
        Point2D(Point2D const& o) : x(o.x),y(o.y){}
       
        void operator+=( Point2D const& other ) {
            x += other.x;
            y += other.y;
        }
    
        void operator-=( Point2D const& other) {
            x -= other.x;
            y -= other.y;
        }
    
        friend Point2D operator+( Point2D const& a, Point2D const& b ) {
            Point2D sum( a );
            sum += b;
            return sum;
        }
    
        friend Point2D operator-( Point2D const&a, Point2D const& b ) {
            Point2D rest( a );
            rest -= b;
            return rest;
        }
        T& x = data.array[0];
        T& y = data.array[1];
        basic_point<T,2> data = basic_point<T,2>(0);  
};

to test it a trivial example can be ran like this

int main(int argc, char* argv[]) {
    const int a[2] = { 1 , 3 };
    const int b[2] = { 1 , 3 }; 
    auto point_a = Point2D(a); 
    auto point_b = Point2D(b);
    auto result = point_a + point_b;
    std::cout << "Result : ("<< result.x << " , " << result.y <<")\n";
    return 0;
}

but it compiles and terminates due to access violation. Any idea why is this happening.

a test can be seen here

Best Answer

You got the pointer arithmetic wrong when you call std::copy in your basic_point::copy method which accepts an array (T const (&p)[dim]).

Instead of:

std::copy(p, p + dim * sizeof(p[0]), array.begin()); 

It should be:

std::copy(p, p + dim, array.begin());

Because when you use operator+ on a pointer (or an array) it automatically takes into account the sizeof of the object the pointer/array points to, therefore p + dim already advances the address by dim elements of size sizeof(p[0]).

The access-violation error you get is because you access the array out-of-bounds (due to the wrong end address).

This live demo is a fixed version of the one you posted: Live demo


Another issue which is not triggered by your test is the call the std::copy in your other basic_point::copy (the one that accepts a basic_point<T,dim> const& p). Your code attempts to use p as if it was a pointer but it is actually a reference (to a point) so it doesn't really makes sense.
I am not sure why this method is even needed, but maybe you meant something like:

std::copy(p.array.begin(), p.array.end(), array.begin());