C++ 对堆栈上分配的变量调用delete

C++ 对堆栈上分配的变量调用delete,c++,stack,heap,delete-operator,C++,Stack,Heap,Delete Operator,忽略编程风格和设计,对堆栈上分配的变量调用delete是否“安全” 例如: int nAmount; delete &nAmount; 或 ,对堆栈分配的变量调用delete是不安全的。您应该只对new创建的内容调用delete 对于每个malloc或calloc,应该只有一个free 对于每个新应该只有一个delete 对于每个new[],应该只有一个delete[] 对于每个堆栈分配,不应该有显式的释放或删除。如果适用,析构函数将自动调用 通常情况下,您不能混合和匹

忽略编程风格和设计,对堆栈上分配的变量调用delete是否“安全”

例如:

   int nAmount;
   delete &nAmount;

,对堆栈分配的变量调用
delete
是不安全的。您应该只对
new
创建的内容调用
delete

  • 对于每个
    malloc
    calloc
    ,应该只有一个
    free
  • 对于每个
    应该只有一个
    delete
  • 对于每个
    new[]
    ,应该只有一个
    delete[]
  • 对于每个堆栈分配,不应该有显式的释放或删除。如果适用,析构函数将自动调用
通常情况下,您不能混合和匹配其中任何一种,例如,对
新的
对象使用no
free
-ing或
delete[]
-ing。这样做会导致未定义的行为。

好吧,让我们试试:

jeremy@jeremy-desktop:~$ echo 'main() { int a; delete &a; }' > test.cpp
jeremy@jeremy-desktop:~$ g++ -o test test.cpp
jeremy@jeremy-desktop:~$ ./test
Segmentation fault

因此,显然这根本不安全。

请记住,当您使用new(或malloc)分配内存块时,实际分配的内存块将大于您要求的内存块。 内存块还将包含一些簿记信息,以便在释放该块时,可以轻松地将其放回空闲池,并可能与相邻的空闲块合并

当您试图释放从new中未接收到的任何内存时,簿记信息将不存在,但系统将按原样运行,结果将不可预测(通常很糟糕)。

否, 应使用delete运算符删除使用new分配的内存 使用malloc分配的数据应该使用free删除。
并且不需要取消分配在堆栈上分配的变量。

这里,内存是使用堆栈分配的,因此不需要实际删除它,但如果您已经动态分配了所有内存

像 int*a=新的int()


然后您必须执行deletea而不是delete&a(a本身就是一个指针),因为内存是从空闲存储区分配的

在windows中玩了一会儿g++4.4之后,我得到了非常有趣的结果:

  • 对堆栈变量调用delete似乎没有任何作用。没有错误抛出,但删除后我可以访问变量而不会出现问题

  • 如果一个类的方法是
    delete this
    ,则如果该对象在堆中分配,则该类将成功删除该对象,但如果该对象在堆栈中分配,则不会成功删除该对象(如果该对象在堆栈中,则不会发生任何事情)


  • 没有人知道会发生什么。这会调用未定义的行为,因此任何事情都可能发生不要这样做。

    天使失去了翅膀。。。您只能在分配了
    new
    的指针上调用
    delete
    ,否则您将得到未定义的行为。

    是的,这是未定义的行为:传递到
    delete
    的任何非来自
    new
    的内容都是UB:

    C++标准,第3.7.3.2.3节: 提供给标准库中提供的某个a解除分配函数的第一个参数的值可以是
    null
    指针值;如果是,并且解除分配函数是标准库中提供的函数,则对解除分配函数的调用无效。否则,在标准库中提供给
    运算符delete(void*)
    的值应是先前调用标准库中的
    运算符new(std::size_t)
    运算符new(std::size_t,const std::nothrow_t&)时返回的值之一


    未定义行为的后果是未定义的。“什么都没发生”的结果和其他任何事情一样有效。然而,通常是“什么也不会马上发生”:释放无效内存块可能会在随后调用分配器时产生严重后果。

    您自己已经回答了这个问题
    delete
    只能用于通过
    new
    获取的指针。做任何其他事情都是简单的未定义行为


    因此,真的没有说会发生什么,从代码运行良好到崩溃,再到擦除硬盘驱动器,都是这样做的有效结果。因此,请不要这样做。

    这是UB,因为您不能对未动态分配new的项目调用delete。就这么简单。

    谢谢!我的编译器没有seg错误,但我肯定怀疑它是否合法。“应该”是一个更好的词。“必须”表示如果缺少free/delete/delete[],malloc/new/new[]将失败,但事实并非如此。“正好一个”的使用意味着我想你会这么做。相关:请注意,你的第二个例子不必在堆栈上。nAmount对于任何内存样本都是本地的。就像在你的眼睛里戳一根锋利的针一样安全。-这就是happensOne kitten在某处被杀的原因。好吧,假设我有一个父/子对象的层次结构树。树负责递归调用不同的对象方法,删除根对象后,所有子对象都应递归删除。但是,有些子对象可能是范围分配的,有些是动态分配的,在这种情况下,不可能区分这两个对象,只删除动态对象,而不添加更多数据来指定它?@ddriver:不,不可能只给一个指针就获得这些信息。您可以将
    std::shared_ptr
    与对非动态对象不做任何操作的自定义删除程序一起使用,或者添加您自己的元数据,或者提出一种不太复杂的生存期管理策略。@ddriver:我通常遵循一条简单的规则:负责对象创建的对象或范围也负责对象的删除。或者说:不要
    删除一个你没有
    新建的对象。@ddriver如果你需要,你的设计是有严重缺陷的。重新思考
    
    jeremy@jeremy-desktop:~$ echo 'main() { int a; delete &a; }' > test.cpp
    jeremy@jeremy-desktop:~$ g++ -o test test.cpp
    jeremy@jeremy-desktop:~$ ./test
    Segmentation fault