包含指针的用户定义对象存储在数组中时中断
User-defined object containing pointer breaks when stored in array
当我在 A
中存储普通 int
并执行简单的获取函数时:
#include <iostream>
class A
{
int p;
public:
void setint(int p_x);
int getint();
};
void A::setint(int p_x) {p = p_x;} // set p (type int)
int A::getint() {return p;} // get p (type int)
int main()
{
A arr_a[5];
arr_a[0].getint();
}
它编译并退出,代码为 0
。但是,当我将 int
更改为 int*
并尝试执行相同操作时:
#include <iostream>
class A
{
int* p;
public:
void setint(int p_x);
int getint();
};
void A::setint(int p_x) {*p = p_x;} // set int pointed to by p (type int)
int A::getint() {return *p;} // get int pointed to by p (type int)
int main()
{
A arr_a[5];
arr_a[0].getint();
}
编译正常,但退出时代码为 3221225477
。为什么会这样,还有什么方法可以将指针存储在 A
中并将 A
存储在数组中?
您的程序有一个严重缺陷。您给定的两个代码片段(问题中的案例 1 和案例 2)都具有 未定义的行为。来看看怎么样
案例一:代码片段 1
在您的代码片段 1 中,由于数据成员 p
是内置类型并且您尚未对其进行初始化,因此 p
具有 垃圾值 并使用(访问)这个值会导致 未定义的行为 这正是你的情况。
当你写道:
A arr_a[5];//this creates a 1D array of size 5 having elements of type `A` but the elements are default initialized
arr_a[0].getint();//this result in undefined behavior
上述语句创建了一个大小为 5 的一维数组,其元素类型为 A
。 问题是因为你没有初始化这个数组,它的元素是默认初始化这意味着数据成员的值p
也是默认初始化的。但是由于您没有对变量 p
使用 in-class 初始值设定项 ,p
具有垃圾值,这会导致 未定义的行为.
您可以通过查看输出来确认这一点 here。
案例一的解决方案
你可以通过使用 in-class initializer 初始化数据成员 p
来解决这个问题,如下所示:
#include <iostream>
class A
{
int p = 0;//USE IN-CLASS INITIALIZER
public:
void setint(int p_x);
int getint();
};
void A::setint(int p_x) {p = p_x;} // set p (type int)
int A::getint() {return p;} // get p (type int)
int main()
{
A arr_a[5];
std::cout<<arr_a[0].getint();//now ok because we have initilaized p
}
案例二:代码片段 2
在这种情况下,唯一的区别是现在数据成员 p
是指向 int 的指针,即 int*
。与上一种情况类似,指针变量有一个垃圾值,如果您尝试像在主函数中那样使用它,可能会导致未定义的行为通过写作:
A arr_a[5];//create a 1D array of objects `A` but the elements(A objects) are default initialized
arr_a[0].getint();//this result in undefined behavior
案例二的解决方案
你可以通过使用 in-class initializer 初始化数据成员 p
来解决这个问题,如下所示:
#include <iostream>
class A
{
int* p = nullptr;//USE IN-CLASS INITIALIZER
public:
void setint(int p_x);
int getint();
//other members like constructor and destructor to allocate and deallocate memory
//so that getint and setint doesn't dereference nullptr
};
void A::setint(int p_x)
{ if(p!=nullptr)// add a check here to see p isn't null
{
*p = p_x;
}
else
{
std::cout<<"WARNING: Dereferencing a nullptr can lead to UB";
}
}
int A::getint() // add a check here to see p isn't null
{ if(p!= nullptr)
{
std::cout<<"yes"<<std::endl;
return *p;
}
else
{
std::cout<<"WARNING: Dereferencing a nullptr can lead to UB";
return -1;
}
}
int main()
{
A arr_a[5];
arr_a[0].getint();//now ok(assuming `p` isn't nullptr) because we have initilaized p
}
总结
您提供的两个代码片段都有未定义的行为。您可以通过使用 in-class initlaizers 将数据成员 p
初始化为默认值来解决这两个问题。
在你的第二种情况下 A arr_a[5]
只需创建一个包含 5 个 A 的数组。但是
对于每个 A,指针是一个未定义的数字(可能是 0x0),因此 *p
是一个未定义的行为。您应该添加 A::A()
和 A::~A()
来管理 class 中的指针
就像这样:
#include <iostream>
class A
{
int *p;
public:
A();
~A();
void setint(int p_x);
int getint();
};
A::A() : p(new int) {}
A::~A() { delete p; }
void A::setint(int p_x) { *p = p_x; } // set int pointed to by p (type int)
int A::getint() { return *p; } // get int pointed to by p (type int)
int main()
{
A arr_a[5];
arr_a[0].getint();
}
当我在 A
中存储普通 int
并执行简单的获取函数时:
#include <iostream>
class A
{
int p;
public:
void setint(int p_x);
int getint();
};
void A::setint(int p_x) {p = p_x;} // set p (type int)
int A::getint() {return p;} // get p (type int)
int main()
{
A arr_a[5];
arr_a[0].getint();
}
它编译并退出,代码为 0
。但是,当我将 int
更改为 int*
并尝试执行相同操作时:
#include <iostream>
class A
{
int* p;
public:
void setint(int p_x);
int getint();
};
void A::setint(int p_x) {*p = p_x;} // set int pointed to by p (type int)
int A::getint() {return *p;} // get int pointed to by p (type int)
int main()
{
A arr_a[5];
arr_a[0].getint();
}
编译正常,但退出时代码为 3221225477
。为什么会这样,还有什么方法可以将指针存储在 A
中并将 A
存储在数组中?
您的程序有一个严重缺陷。您给定的两个代码片段(问题中的案例 1 和案例 2)都具有 未定义的行为。来看看怎么样
案例一:代码片段 1
在您的代码片段 1 中,由于数据成员 p
是内置类型并且您尚未对其进行初始化,因此 p
具有 垃圾值 并使用(访问)这个值会导致 未定义的行为 这正是你的情况。
当你写道:
A arr_a[5];//this creates a 1D array of size 5 having elements of type `A` but the elements are default initialized
arr_a[0].getint();//this result in undefined behavior
上述语句创建了一个大小为 5 的一维数组,其元素类型为 A
。 问题是因为你没有初始化这个数组,它的元素是默认初始化这意味着数据成员的值p
也是默认初始化的。但是由于您没有对变量 p
使用 in-class 初始值设定项 ,p
具有垃圾值,这会导致 未定义的行为.
您可以通过查看输出来确认这一点 here。
案例一的解决方案
你可以通过使用 in-class initializer 初始化数据成员 p
来解决这个问题,如下所示:
#include <iostream>
class A
{
int p = 0;//USE IN-CLASS INITIALIZER
public:
void setint(int p_x);
int getint();
};
void A::setint(int p_x) {p = p_x;} // set p (type int)
int A::getint() {return p;} // get p (type int)
int main()
{
A arr_a[5];
std::cout<<arr_a[0].getint();//now ok because we have initilaized p
}
案例二:代码片段 2
在这种情况下,唯一的区别是现在数据成员 p
是指向 int 的指针,即 int*
。与上一种情况类似,指针变量有一个垃圾值,如果您尝试像在主函数中那样使用它,可能会导致未定义的行为通过写作:
A arr_a[5];//create a 1D array of objects `A` but the elements(A objects) are default initialized
arr_a[0].getint();//this result in undefined behavior
案例二的解决方案
你可以通过使用 in-class initializer 初始化数据成员 p
来解决这个问题,如下所示:
#include <iostream>
class A
{
int* p = nullptr;//USE IN-CLASS INITIALIZER
public:
void setint(int p_x);
int getint();
//other members like constructor and destructor to allocate and deallocate memory
//so that getint and setint doesn't dereference nullptr
};
void A::setint(int p_x)
{ if(p!=nullptr)// add a check here to see p isn't null
{
*p = p_x;
}
else
{
std::cout<<"WARNING: Dereferencing a nullptr can lead to UB";
}
}
int A::getint() // add a check here to see p isn't null
{ if(p!= nullptr)
{
std::cout<<"yes"<<std::endl;
return *p;
}
else
{
std::cout<<"WARNING: Dereferencing a nullptr can lead to UB";
return -1;
}
}
int main()
{
A arr_a[5];
arr_a[0].getint();//now ok(assuming `p` isn't nullptr) because we have initilaized p
}
总结
您提供的两个代码片段都有未定义的行为。您可以通过使用 in-class initlaizers 将数据成员 p
初始化为默认值来解决这两个问题。
在你的第二种情况下 A arr_a[5]
只需创建一个包含 5 个 A 的数组。但是
对于每个 A,指针是一个未定义的数字(可能是 0x0),因此 *p
是一个未定义的行为。您应该添加 A::A()
和 A::~A()
来管理 class 中的指针
就像这样:
#include <iostream>
class A
{
int *p;
public:
A();
~A();
void setint(int p_x);
int getint();
};
A::A() : p(new int) {}
A::~A() { delete p; }
void A::setint(int p_x) { *p = p_x; } // set int pointed to by p (type int)
int A::getint() { return *p; } // get int pointed to by p (type int)
int main()
{
A arr_a[5];
arr_a[0].getint();
}