Нарушение прав доступа с использованием шаблона класса Basic_point

стремясь создать собственный тип точки, написал следующее:

поэтому, прежде всего, используя концепцию для ограничения типа

//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>;
};

базовый шаблон точки, просто оболочка вокруг массива

// 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;
};

Затем специальный шаблон явно управляет 2d-точкой, где x и y относятся к элементам 0 и 1 массива, используя композицию, без наследования.

//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);  
};

чтобы проверить это, можно запустить тривиальный пример следующим образом

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;
}

но он компилируется и завершается из-за нарушения прав доступа. Есть идеи, почему это происходит.

тест можно посмотреть здесь

Когда вы обнаруживаете сбой в своем отладчике, в каком месте вашего кода это происходит? Каковы значения всех задействованных переменных?

Some programmer dude 29.07.2024 14:41

Наличие ссылочных типов членов вызывает проблемы, вы не можете их повторно связать, и все сгенерированные компилятором операторы копирования/перемещения недействительны, а ваш определенный конструктор копирования неверен, поскольку он инициализирует ссылку, а не объект, на который ссылается.

Ahmed AEK 29.07.2024 15:03
x = data.array[0]; y = data.array[1]; в конструкторе делает не то, что вы думаете. x и y уже связаны, вы назначаете эти объекты себе.
Caleth 29.07.2024 15:08

Кажется, у вас есть довольно фундаментальные непонимания того, как работает C++. Какие ресурсы вы использовали для изучения основ C++? Возможно, вы захотите их обновить.

Some programmer dude 29.07.2024 15:15

@Someprogrammerdude работает над этим ;)

Amin Ben 29.07.2024 15:31

@AhmedAEK Я не вижу другого способа получить доступ к значению из массива быстрее и удобнее для пользователя, чем point.x. и точка.й.

Amin Ben 29.07.2024 15:36

@Калет, извини, строки остались из предыдущей версии, где я пытался защитить массив...

Amin Ben 29.07.2024 15:38

вы можете определить функции доступа: T& x() { return data.array[0]; }. Тогда Point2D является регулярным. Это не медленнее, чем привязка ссылок как членов данных.

Caleth 29.07.2024 15:41

Я обнаружил, что удаление массива гораздо более удобно для пользователя, вам никогда не понадобится точка бесконечного размера, и люди склонны использовать x гораздо чаще, чем data, для любого 2D/3D API

Ahmed AEK 29.07.2024 15:44

предположим, что у меня есть облако точек из 1 миллиона точек, которыми я хочу манипулировать, используя массив даже для двух атрибутов x и y, заставить их склеиться в памяти, лучше, верно?

Amin Ben 29.07.2024 16:13
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
11
93
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы неправильно выполнили арифметику указателей, когда вызывали std::copy в своем методе basic_point::copy, который принимает массив (T const (&p)[dim]).

Вместо:

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

Должен быть:

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

Потому что когда вы используете operator+ для указателя (или массива), он автоматически учитывает sizeof объекта, на который указывает указатель/массив, поэтому p + dim уже продвигает адрес на dim элементы размера sizeof(p[0]).

Ошибка нарушения прав доступа, которую вы получаете, связана с тем, что вы обращаетесь к массиву за пределами границ (из-за неправильного конечного адреса).

Эта живая демонстрация представляет собой исправленную версию той, которую вы опубликовали: Live demo


Другая проблема, которая не вызвана вашим тестом, — это вызов std::copy в другом basic_point::copy (том, который принимает basic_point<T,dim> const& p). Ваш код пытается использовать p, как если бы это был указатель, но на самом деле это ссылка (на точку), поэтому это не имеет смысла.
Я не уверен, зачем вообще нужен этот метод, но, возможно, вы имели в виду что-то вроде:

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

Спасибо. теперь выглядит лучше демо

Amin Ben 29.07.2024 15:43

Рад был помочь. Кстати, в первой перегрузке copy вы можете использовать p.array.end() вместо p.array.begin() + dim (это последняя строка в моем обновленном ответе).

wohlstad 29.07.2024 15:47

Другие вопросы по теме