什么是悬垂指针?

cod*_*her 43 c++ pointers dangling-pointer

我知道这是很常见的问题,但对我来说还是新的!

我不明白悬挂指针的概念,谷歌搜索,并编写测试方法找到一个.

我只是想知道这是一个悬垂的指针吗?无论我发现什么样的东西都回来了,我在这里尝试类似的东西!

谢谢!

void foo(const std::string name)
{
    // will it be Dangling pointer?!, with comments/Answer
    // it could be if in new_foo, I store name into Global.
    // Why?! And what is safe then?
    new_foo(name.c_str());
}

void new_foo(const char* name)
{
    // print name or do something with name...   
}
Run Code Online (Sandbox Code Playgroud)

Jac*_*ack 55

悬空指针是指向无效数据或指向无效数据的指针,例如:

Class *object = new Class();
Class *object2 = object;

delete object;
object = nullptr;
// now object2 points to something which is not valid anymore
Run Code Online (Sandbox Code Playgroud)

即使在堆栈分配的对象中也会发生这种情

Object *method() {
  Object object;
  return &object;
}

Object *object2 = method();
// object2 points to an object which has been removed from stack after exiting the function
Run Code Online (Sandbox Code Playgroud)

c_str如果字符串之后被修改或被销毁,则返回的指针可能变为无效.在你的例子中,你似乎没有对它进行修改,但由于不清楚你将要做什么,const char *name因此不可能知道你的代码本质上是否安全.

例如,如果将指针存储在某处,然后销毁相应的字符串,则指针变为无效.如果const char *name仅在范围内使用new_foo(例如,出于打印目的),则指针将保持有效.

  • +(1/2)这个答案.最初的解释是好的.最后的建议是偏执和不必要的.OP的代码是安全的. (2认同)
  • @BenjaminLindley*......鲁莽且不必要的不​​安全*.使用`strdup`解决`std :: string`非常荒谬. (2认同)
  • @codemuncher:当`foo`返回时,`global_name`成为一个悬空指针,因为指针起源的字符串(`foo`中的`string name`)在那时被销毁. (2认同)
  • @codemuncher我不确定你想“安全”地做什么。规则很简单:所有指针必须为空或指向有效的“对象”。(我使用“对象”是因为它在 C++ 标准中使用。)当您删除某些内容时,您必须确保(根据设计)没有指向它的指针继续存在。关于“std::string::c_str()”的返回值:您应该使用此函数的_唯一_时间是在连接到需要“char const *”的遗留函数时。 (2认同)

Mik*_*lya 10

悬空指针是一个(非NULL)指针,指向未分配(已释放)的内存区域.

鉴于字符串未通过new_foo修改,上面的示例应该是正确的.


Ash*_*uja 7

取自这里。虽然,即使这是针对 C 的,对于 C++ 也是一样的。

悬空指针

当一个指针指向一个变量的内存地址但一段时间后该变量从该内存位置删除而指针仍然指向它时,这样的指针被称为悬空指针,这个问题被称为悬空指针问题。

最初

在此处输入图片说明

之后

在此处输入图片说明

例子

#include<stdio.h>

int *call();
int main() {

  int *ptr;
  ptr = call();

  fflush(stdin);
  printf("%d", *ptr);
  return 0;
}

int * call() {
  int x=25;
  ++x;

  return &x;
}
Run Code Online (Sandbox Code Playgroud)

它的输出将是垃圾,因为该变量x是一个局部变量。它的范围和生命周期在函数调用中,因此在返回x变量的地址后,它x变成死的,指针仍然指向那个位置。

  • “悬空指针”是 C 中最有害的问题之一,也是 C++ 创建引用的原因之一。遗憾的是,引用也可能以同样的方式变得悬而未决。智能指针(https://en.wikipedia.org/wiki/Smart_pointer)是处理该问题的一种方法。不幸的是,随后的行为是未定义的,因此有时结果会变成“垃圾”(如果程序的另一部分使用该内存区域),有时则不会。这导致了一种难以复制的错误,让人抓狂。 (2认同)

Goo*_*tan 7

悬空指针是指堆栈中存在有效指针,但指向无效内存的情况。当您在释放堆栈中的指针之前释放堆内存时,您可能会遇到这种情况。

这是一个安全问题。因为当您释放内存时,我们正在通知操作系统,我们不再需要这部分内存。因此操作系统会将该块内存标记为准备分配,并在其他应用程序请求内存时分配给它们。

通常,在 C++ 中,通过通用模式分配和释放内存。当类初始化时,会调用类中的构造函数,这是在堆中分配内存的正确位置。当类实例超出范围时,将调用析构函数,这是从堆中释放内存的正确位置。假设我们已经创建了一个类,它分别在构造函数和析构函数中分配和释放内存。

int main() {
  SomeClass pointer1 = SomeClass();
  SomeClass pointer2 = pointer1;
}
Run Code Online (Sandbox Code Playgroud)

在上面的示例代码中,声明了两个变量,但它们都具有相同的值。当构造函数被调用时,它会分配一块堆内存。然后我们声明另一个变量并分配相同的值。在 C++ 中,通常,当您分配复杂类型的值时,它会执行浅复制(除非您显式实现复制构造函数)而不是深复制。这意味着唯一的指针被复制到堆栈中,而不是堆内存中。实际上出于性能原因不建议复制堆内存。现在,最终的内存布局看起来像我们有两个指针指向同一堆内存。

现在,当函数执行完成时,局部变量超出范围并调用析构函数。首先,pointer2 调用析构函数来释放堆内存。此时,pointer1就变成了悬空指针。它指向已经释放的内存。

从这个例子中,我们了解到悬空指针的主要原因是同一资源有多个所有者。因为当一个指针释放内存时,其他指针就变成了悬空指针。


MSa*_*ers 5

作为一种风格,我将悬空指针解释为“一个仍然存在的指针,即使它指向的对象不再存在”。

在您的情况下,指针name存在的时间比它指向的对象要短。所以它永远不会悬空。

在常见的 C++ 类中,指针会在很短的时间内在析构函数中悬空。那是因为该delete语句}在析构函数的最后一个之前,而指针本身在最后一个}. 如果您不想担心这一点,请使用 eg unique_ptr<T>。该T*指针将吊着的内部很短的时间unique_ptr::~unique_ptr析构函数,这是完全安全的。