C ++和何时使用删除
我刚刚重新阅读了一些C ++代码(我现在在学校学习Java),并且对于何时必须使用delete有点困惑。
例如:声明两个对象时:
Fraction* f1;
Fraction* f2;
并像这样创建f1和f2:
f1 = new Fraction(user_input1, user_input2);
f2 = new Fraction(user_input3, user_input4);
下一次我想使用new
操作符创建一个新对象时,是否必须先删除? 我很困惑,因为我习惯于让java中的垃圾回收器负责处理对象并删除它们。 我需要删除才能再次使用新的?
if (f1) delete f1;
if (f2) delete f2;
//initialize again...
经验法则是每个new
必须有相应的delete
。
在C ++中手动使用new
和delete
不是常见的事情。 当你初始化的事情,而无需使用new
或delete
其保证是由即将来处理你}
。 假设每个人都在做他们的工作,并且遵循RAII的原则。
Fraction f1(...);
实例化一个名为f1的Fraction对象。 它的析构函数在到达范围的末尾时会被调用。
'现代'的做法是处理上述事情。 在极少数情况下,这种方法不行,你应该使用智能指针。
有两种主要的方法来创建C ++选项。 一个在堆栈中(即Fraction f1;
),并且当该堆栈帧被弹出时该内存被自动释放。 第二个是在堆上(即Fraction* f1 = new Fraction();
键是new
关键字。
基本的总结是这样的:你的new
的和delete
s必须匹配。 每当你有new
东西,你必须delete
它,当你完成它。 “当你完成它时”由你来决定。 但是,如果您重新使用变量(请参见下文),则需要先delete
变量,否则无法将原始对象恢复为delete
。
Fraction* f1 = new Fraction(); // create memory on heap, will need to free
f1 = new Fraction(); // this is a memory leak because I didn't first free the
// original f1 object, which I can no longer access
而不是告诉你何时使用delete
,我会尽力解释为什么你使用指针。 因此,您可以决定何时使用动态对象,如何使用它们以及何时调用delete
(而不是)。
规则的拇指:
delete
电话。 new
也可以在合适的位置写下delete
文件(并确保被调用)。 new
关键字,都需要有一个delete
关键字。 否则,您正在使用机器的所有资源,导致应用程序崩溃或停止。 它也会使系统变慢。 静态创建一个对象:
Fraction f1;
动态创建对象:
Fraction* f1;
现在你有这个地址到堆上的内存块。 这是无效的,因为你没有分配任何东西。 好的做法是 - 根据你声明的位置 - 分配一个NULL(窗口)或0(跨平台)。
Fraction* f1 = 0;
何时使用delete
只要你创建一个动态对象,从而调用new
操作符,就需要在某处调用delete
。
int main()
{
Fraction* f1 = 0; // Good practise to avoid invalid pointers
// An invalid pointer - if( f1 ){ Access violation }
f1 = new Fraction(); // Could have done this at the previous line
/* do whatever you need */
if( f1 )
{
delete f1;
f1 = 0; // not needed since we are leaving the application
}
return 0;
}
在某些情况下,有一个Fraction数组或指针指向它可能是有用的。 这里使用int来简化,与跳过错误处理相同:
int arr[ 10 ];
int cur = -1;
int* Add( int fraction )
{
arr[++cur] = fraction;
return &arr[cur];
}
// Usage:
Add( 1 );
Add( 4 );
有一件事发生在这里,没有通过动态对象分配给任何内存。 它们被自动释放。 函数返回的指针是指向静态内存块的指针。
当把arr指向int的指针时:
int* arr[ 10 ];
int cur = -1;
int* Add( int* fraction )
{
arr[++cur] = fraction;
return arr[cur];
}
// Usage:
int* test;
test = Add( new int( 1 ) );
test = Add( new int( 4 ) );
现在你必须记忆块因为没有清理代码而泄漏。
在每次Add(...)
delete test
后调用时,您已经清理了内存,但是您已经将int* arr[ 10 ]
存储的值丢失,因为它们指向保存该值的内存。
您可以创建另一个函数并在完成这些值后调用它:
void CleanUp()
{
for( int a = 0; a < 10; ++a )
delete arr[ a ];
}
小用法示例:
int* test;
int test2;
test = Add( new int( 1 ) );
test2 = *Add( new int( 4 ) ); // dereference the returned value
/* do whatever you need */
CleanUp();
我们为什么要使用指针:
int Add( int val )
{
return val; // indeed very lame
}
当你调用一个需要参数(类型)的函数时,你并没有传入实例,而是传入它的一个副本。 在上述功能中,您将返回该副本的副本。 它会占用大量的所有内存,导致应用程序的速度大大降低。
考虑这个:
class Test
{
int t;
char str[ 256 ];
}
如果一个函数需要一个类型Test,那么你需要复制int和256个字符。 因此,使该函数只需要一个指向Test的指针。 然后使用指针指向的内存并且不需要复制。
int Add( int val )
{
val++;
return val;
}
在最后一个例子中,我们将val的副本加1,然后返回该副本。
int i = Add( 1 );
结果: i = 2;
void Add( int* val )
{
// mind the return type
*val++;
}
在这个例子中,您将地址传递给一个值,然后 - 在取消引用之后 - 将值加1。
int i = 1;
Add( &i );
结果: i = 2;
现在你已经把地址传给了i
,而不是复制它。 在该函数中,您直接将1添加到该内存块的值。 因为你已经改变了记忆本身,所以你什么也没有返
归零/测试有效指针
有时您会遇到以下示例:
if( p != 0 ) // or if( p )
{
/* do something with p */
}
这只是为了检查指针p是否有效。 但是,无效地址 - 因此不指向您保留的内存(访问冲突) - 也会通过。 对于您的代码,无效指针是有效的地址。
因此,要使用这样的检查,你必须使用NULL(或0)指针。
Fraction* f1 = 0;
当f1 == 0时,它不指向任何东西,否则它指向它指向的任何东西。
当你在一个'main'类中有一个指针或者没有被创建时,这是有用的。
class Fraction
{
public:
int* basicFeature;
int* ExtendedFeature = 0; // NULL this pointer since we don't know if it
// will be used
Fraction( int fraction )
{
// Create a pointer owned by this class
basicFeature = new int( fraction );
}
Fraction( int fraction, int extended ) // mind the static
: Fraction( fraction )
{
// Create a pointer owned by this class
ExtendedFeature = new int( extended );
}
~Fraction()
{
delete basicFeature;
if( ExtendedFeature )
// It is assigned, so delete it
delete ExtendedFeature;
}
}
由于我们正在创造两个指针,因此我们正在清理那些指针。 只有检查ExtendedFeature,因为这个可能会或可能不会被创建。 basicFeature总是被创建。
你可以通过调用一个新函数来替换if语句,包括它在dtor中的作用域: removeExtendedFeature()
函数实现的位置:
Fraction::removeExtendedFeature()
{
if( ExtendedFeature )
{
// It is assigned, so delete it
delete ExtendedFeature;
// Now it is important to NULL the pointer again since you would
// get an access violation on the clean up of the instance of
// the class Fraction
ExtendedFeature = 0;
}
}
而新的dtor:
Fraction::~Fraction()
{
delete basicFeature;
removeExtendedFeature();
}
置零的另一个功能可能是:
int Fraction::getValue()
{
int result = *basicFeature;
if( ExtendedFeature )
result += *ExtendedFeature;
return result;
}
我为跛级班级道歉,还有一个更加蹩脚的扩展功能。 但作为一个例子,它可以达到目的。
链接地址: http://www.djcxy.com/p/96539.html上一篇: C++ and when to use delete
下一篇: What is safe? returning a structure or the pointer from a function