qno*_*nob 9 c++ new-operator delete-operator
我刚刚在C++上重读了一些代码(我现在正在学校学习Java),而且当我必须使用删除时,我有点困惑.
例如:声明两个对象时:
Fraction* f1;
Fraction* f2;
Run Code Online (Sandbox Code Playgroud)
并像这样创建f1和f2:
f1 = new Fraction(user_input1, user_input2);
f2 = new Fraction(user_input3, user_input4);
Run Code Online (Sandbox Code Playgroud)
下次我想使用newoperator创建一个新对象时,是否必须先删除?我很困惑,因为我习惯在java中使用垃圾收集器来处理对象及其删除.在重新使用新内容之前是否必须删除?
if (f1) delete f1;
if (f2) delete f2;
//initialize again...
Run Code Online (Sandbox Code Playgroud)
bra*_*low 14
而不是告诉你何时使用delete,我会尝试解释你为什么使用指针.因此,您可以决定何时使用动态对象,如何使用它们以及何时调用delete(而不是).
规则大拇指:
delete电话.new也要delete在适当的位置写一些(并确保调用它).new关键字,都需要有一个delete关键字.否则,您将获取机器所具有的所有资源,导致应用程序崩溃或停止.它也会使系统变慢.静态创建对象:
Fraction f1;
Run Code Online (Sandbox Code Playgroud)
动态创建对象:
Fraction* f1;
Run Code Online (Sandbox Code Playgroud)
现在,您将此地址写入堆上的内存块.它是无效的,因为您没有为其分配任何内容.好的做法是 - 取决于你声明它的位置 - 为它分配一个NULL(窗口)或0(跨平台).
Fraction* f1 = 0;
Run Code Online (Sandbox Code Playgroud)
何时使用 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;
}
Run Code Online (Sandbox Code Playgroud)
在某些情况下,拥有一个Fraction数组或指向它的指针可能很有用.这里使用int来简化,与跳过错误处理相同:
int arr[ 10 ];
int cur = -1;
int* Add( int fraction )
{
arr[++cur] = fraction;
return &arr[cur];
}
// Usage:
Add( 1 );
Add( 4 );
Run Code Online (Sandbox Code Playgroud)
这里发生了一件事,没有通过动态对象分配任何内存.它们会自动释放.函数返回的指针是指向静态内存块的指针.
将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 ) );
Run Code Online (Sandbox Code Playgroud)
现在你需要内存块泄漏,因为你没有清理代码.
当你之后的每个调用Add(...)的delete test,你已经清理内存,但你已经失去了你已经存储中的值int* arr[ 10 ],因为它们都指向记忆保持的值.
您可以创建另一个函数,并在完成这些值后调用它:
void CleanUp()
{
for( int a = 0; a < 10; ++a )
delete arr[ a ];
}
Run Code Online (Sandbox Code Playgroud)
小用法示例:
int* test;
int test2;
test = Add( new int( 1 ) );
test2 = *Add( new int( 4 ) ); // dereference the returned value
/* do whatever you need */
CleanUp();
Run Code Online (Sandbox Code Playgroud)
为什么我们要使用指针:
int Add( int val )
{
return val; // indeed very lame
}
Run Code Online (Sandbox Code Playgroud)
当您调用需要参数(类型)的函数时,您不是传入实例而是传递它的副本.在上面的函数中,您将返回该副本的副本.所有涉及的内存都会造成很多重复,你的应用程序会非常慢.
考虑一下:
class Test
{
int t;
char str[ 256 ];
}
Run Code Online (Sandbox Code Playgroud)
如果函数需要类型Test,则复制int和256个字符.因此,使函数只需一个指向Test的指针.然后使用指针指向的存储器,不需要复制.
int Add( int val )
{
val++;
return val;
}
Run Code Online (Sandbox Code Playgroud)
在最后一个示例中,我们在val的副本中添加1,然后返回该副本.
int i = Add( 1 );
Run Code Online (Sandbox Code Playgroud)
结果: i = 2;
void Add( int* val )
{
// mind the return type
*val++;
}
Run Code Online (Sandbox Code Playgroud)
在此示例中,您将地址传递给值,然后 - 在解除引用后 - 向值中添加一个.
int i = 1;
Add( &i );
Run Code Online (Sandbox Code Playgroud)
结果: i = 2;
现在你已经传递了地址i,而不是复制它.在函数中,您直接将1添加到该内存块的值.因为你改变了内存本身,你什么都不返回.
取消/测试有效指针
有时您会遇到以下示例:
if( p != 0 ) // or if( p )
{
/* do something with p */
}
Run Code Online (Sandbox Code Playgroud)
这只是为了检查指针p是否有效.但是,无效的地址 - 因此不指向您保留的内存(访问冲突) - 也将通过.对于您的代码,无效指针是有效地址.
因此,要使用这样的检查,您必须使用NULL(或0)指针.
Fraction* f1 = 0;
Run Code Online (Sandbox Code Playgroud)
当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;
}
}
Run Code Online (Sandbox Code Playgroud)
我们正在创建两个指针,所以在dtor中我们正在清理那些指针.仅检查ExtendedFeature,因为可能会创建或不创建此功能.始终创建basicFeature.
您可以通过调用一个新函数替换dtor中包含其范围的if语句: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;
}
}
Run Code Online (Sandbox Code Playgroud)
而新的dtor:
Fraction::~Fraction()
{
delete basicFeature;
removeExtendedFeature();
}
Run Code Online (Sandbox Code Playgroud)
归零的另一个功能可能是:
int Fraction::getValue()
{
int result = *basicFeature;
if( ExtendedFeature )
result += *ExtendedFeature;
return result;
}
Run Code Online (Sandbox Code Playgroud)
我对蹩脚的Fraction类表示道歉,并且具有更加蹩脚的扩展功能.但作为一个例子,它将达到目的.
创建C++选项有两种主要方法.一个在堆栈(即Fraction f1;)上,当弹出该堆栈帧时,该内存会自动释放.第二个是在堆上(即Fraction* f1 = new Fraction();.键是new关键字.
基本的总结是这样的:你的news和deletes必须匹配.每当你完成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
Run Code Online (Sandbox Code Playgroud)
经验法则是每个new必须有一个对应的delete.
使用手动new和delete是不是在C++做一个平常的事.当您在不使用的情况下初始化内容时,new或者delete保证在即将到来时为您处理}.假设每个人都在做自己的工作,并且在涉及对象时遵循RAII原则.
Fraction f1(...);
Run Code Online (Sandbox Code Playgroud)
实例化一个名为f1的Fraction对象.它的析构函数将在到达范围结束时被调用.
"现代"方法是处理上述事情.在极少数情况下,这种方法不起作用,你应该使用智能指针.
您需要删除指针指向的对象。
然后您可以使用另一个对象进行创建,但稍后new不要忘记。delete:)
删除之前真的需要检查吗?请务必阅读此答案,它实际上说不。此外,一个好的做法是将指针(在 后面delete)设置为 NULL,以供将来使用。
new那么,如果对同一个指针使用两次会发生什么?
回想一下,new它将根据我们的要求分配尽可能多的内存。然后,我们需要知道这段内存在哪里。为此,new返回指向该内存的指针。
那么,假设您这样做:
f1 = new Fraction(user_input1, user_input2);
f1 = new Fraction(user_input1, user_input2);
delete(f1);
Run Code Online (Sandbox Code Playgroud)
可以吗?不。
new内存。f1new将覆盖指针的值,导致f1指向我们分配的新内存块。delete并且内存被解除分配......但是等等,哪个内存?第二个new给我们的。new?我们无法访问它,因为我们没有保留指向该内存块的指针。记住
new您使用的关键字一样多的内容!正如 WhozCraig 的评论,您应该在动态创建对象(requirenew和delete)和静态创建对象(自动完成)之间做出明智的选择。
| 归档时间: |
|
| 查看次数: |
8459 次 |
| 最近记录: |