C++ 删除这些指针时出错
我知道当我用new初始化指针时,我需要删除指针,否则会发生内存泄漏。我有一个这样设置的类:C++ 删除这些指针时出错,c++,pointers,C++,Pointers,我知道当我用new初始化指针时,我需要删除指针,否则会发生内存泄漏。我有一个这样设置的类: class foobar { private: //! Pointer to the global nodal list int *p_test1; //! Pointer to the global block label list int *p_test2; public: foobar(int *test1, int *test2) {
class foobar
{
private:
//! Pointer to the global nodal list
int *p_test1;
//! Pointer to the global block label list
int *p_test2;
public:
foobar(int *test1, int *test2)
{
p_test1 = test1;
p_test2 = test2;
}
~foobar()
{
delete p_test1;
delete p_test2;
}
};
现在,当调用析构函数时,程序崩溃,控制台显示程序退出,返回代码为-6
“调试”窗口声明:
程序接收信号SIGABRT
当我完成调用堆栈时,最后一项是析构函数。堆栈似乎试图释放内存,但失败
我想知道为什么会这样?在类设置中释放内存的首选方法是什么
另外,如果我注释掉析构函数中的代码,那么当foobar类的实例完成时,指针当然不会被释放。但是,当我调用该类的另一个实例时(假设该实例的创建是由用户按下GUI上的按钮决定的),那么程序就会崩溃。再说一遍,这是为什么?我有一种感觉,这与没有正确地销毁指针有关。正如在评论中提到的,本例中没有新的内容,因此很难解释
new
和delete
之间的平衡
规则是,如果新建指针,则应将其删除
int * p = new int( 5 );
std::cout << "The value of p is " << *p << std::endl;
delete p;
void somefunction( int * p )
{
std::cout << "The value of p is " << *p << std::endl;
delete p; // this looks smelly - deleting a pointer which was allocated.
}
尽管上面的例子打破了5的规则
第五条规则(或零)
上面的PointerHolder的问题是,它没有实现所有5个特殊运算符
PointerHolder a( 12 );
PointerHolder b( 10 );
a = b; // What is going to happen?????
a获取b指针的值,当第二个指针被销毁时,它是对同一块内存的第二次删除,程序崩溃
5规则规定,如果您实现了析构函数
、移动运算符
、复制构造函数
、或运算符=
,则应实现(或删除所有这些运算符)
在这种情况下,删除移动和复制操作符将生成一个简单的唯一\u ptr
零的规则是,如果一个类实现了所有的操作符,或者没有实现任何操作符,那么该类更易于重用
如果您只需要实现一些操作符,那么很可能您还没有识别“资源”——它应该是一个包含所有5个重载操作符的单一类
PointerHolder a( 12 );
PointerHolder b( 10 );
a = b; // What is going to happen?????
现代C++
由于C++11,new和delete的使用被认为仅限于库编写者。由于使用了
std::shared\u ptr
和std::unique\u ptr
为您管理新的删除生命周期,因此您可以专注于手头的问题。您真的分配了memeory吗?您在代码中的何处使用了新运算符?在析构函数中使用指针的delete
,表示对象的所有权。现在我们看到您正在向对象传递一个指针并存储它,是谁分配的?相关的new
在哪里?在代码中,我调用一个函数,返回指向对象的指针。对象本身不是指针。该对象属于另一个类。当此对象发生析构函数时,我不想删除该对象。我只想将这些指针重置回“零”或删除它们。不要用散文来描述您的代码。这是一个相当奇怪的C++代码设计,远远没有什么现代C++ 11后的源码应该看看。考虑不要使用<代码>新建/删除< />代码,如果你不能避免它(通常你应该能够很好地拥有良好的总体架构),那么我宁愿保持<代码>新+删除>代码>在同一个源中的对应对,彼此靠近。此时,你有new
谁知道在哪里,这里有delete
,这将使阅读和审查此类源代码变得困难,必须使用大量的推理来查看每个new
是否与delete
正确配对(显然,当你遇到崩溃时,它已经不是了)。