自定义basic_point模板类触发Access Violation问题求助
我尝试自定义点类型,先通过Numeric概念约束类型,实现封装数组的basic_point模板类,再通过组合方式实现关联数组元素的Point2D模板类。测试代码编译通过,但运行时触发Access Violation,请问原因是什么?
// 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; }; //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; }
核心原因分析
成员初始化顺序错误导致悬垂引用
C++类成员的初始化顺序严格遵循声明顺序,而非构造函数初始化列表或类内初始化的顺序。在Point2D中,x和y的声明早于data,因此x = data.array[0]和y = data.array[1]会先执行,此时data尚未完成构造,data.array属于未初始化的内存空间,引用绑定到了无效地址,后续访问x、y时必然触发Access Violation。basic_point的copy函数参数越界
在basic_point的copy(basic_point<T,dim> const& p)函数中,std::copy(p, p + dim * sizeof(p[0]), array.begin())存在严重错误:p是basic_point对象,并非指针,直接对其做指针算术运算会将对象地址当作数组起始地址,计算出的结束地址会严重超出有效内存范围,导致std::copy访问越界内存,引发运行时错误。Point2D拷贝构造函数引用初始化错误
Point2D的拷贝构造函数Point2D(Point2D const& o) : x(o.x),y(o.y){}试图直接初始化引用成员x、y,但引用成员必须绑定到有效对象的内存,此处写法本质是尝试赋值(而非绑定),且因初始化顺序问题,data未构造完成时x、y的绑定仍无效。
修复建议
- 调整
Point2D的成员声明顺序,将data放在x、y之前:basic_point<T,2> data = basic_point<T,2>(0); T& x = data.array[0]; T& y = data.array[1]; - 修正
basic_point的copy函数参数,使用数组的迭代器或正确指针:constexpr auto inline copy( basic_point<T,dim> const& p) { std::copy(p.array.begin(), p.array.end(), array.begin()); } auto inline copy( T const (&p)[dim]) { std::copy(std::begin(p), std::end(p), array.begin()); } - 修正
Point2D的拷贝构造函数,确保先初始化data再绑定引用:Point2D(Point2D const& o) : data(o.data), x(data.array[0]), y(data.array[1]){}
内容的提问来源于stack exchange,提问作者user6777901

