1. 在遗留代码中删除后使用 NULL 而没有任何智能指针来防止悬空指针总是明智的吗? (排除遗留代码的不良设计架构)

     int* var = new int(100); delete var; var = NULL;
  2. 它在析构函数中也有意义吗?

  3. 在 getter 中,在第二步中测试 NULL 是否有意义? 或者无论如何它是未定义的行为?

      Foo* getPointer() {  
             if (m_var!=NULL) { // <-is this wise
                 return m_var;
             }  
               else {
               return nullptr;
            }
        }
  1. 作为替代方案,这种形式主义又如何呢? 在什么情况下会崩溃?
    Foo* getPointer() {  
             if (m_var) { // <-
                 return m_var;
             }  
               else {
               return nullptr;
            }
        }

  1. (编辑)示例 3./4 中的代码是否会崩溃。 如果 A. 删除后使用 NULL 或 B. 删除后不使用 NULL。

#1楼 票数:3

  1. 在遗留代码中删除后使用 NULL 而没有任何智能指针来防止悬空指针总是明智的吗? (排除遗留代码的不良设计架构)
 int* var = new int(100); // ... delete var; var = NULL;

只有在您之后测试var时才有用。 如果范围结束,或者如果您设置了其他值,则不需要设置为 null。

  1. 它在析构函数中也有意义吗?

析构函数中的无效成员是无用的,因为之后无论如何都无法在没有 UB 的情况下访问它们。 (但这可能有助于调试器)

  1. 在 getter 中,在第二步中测试 NULL 是否有意义? 或者无论如何它是未定义的行为? [..]
  2. [..]

if (m_var != NULL)if (m_var)是等价的。

这是不需要的,因为,如果指针是nullptr ,则返回nullptr ,如果指针不是nullptr ,则返回该指针,因此您的 getter 可以简单地

return m_var;

#2楼 票数:1

避免编写这样的代码

int* var = new int(100);            
// ... do work ...
delete var;

如果“ do work ”抛出、 return s 或以其他方式超出当前范围(现在可能不是这种情况,但稍后“ do work ”需要扩展/更改时),这很容易发生内存泄漏。 始终将堆分配的对象包装在RAII 中,以便析构函数始终在作用域退出时运行,从而释放内存。

如果您确实有这样的代码,那么在 Debug 版本中将var设置为 NULL 甚至更好的错误值(如 -1)可以帮助捕获释放后使用和双重删除错误。

如果是析构函数:

不需要在析构函数中将指针设置为NULL

  • 在生产代码中,这是浪费 CPU 时间(写入一个永远不会被再次读取的值)。

  • 在调试代码中,它使捕获双重删除变得更加困难。 一些编译0xDDDDDDDD0xDDDDDDDD这样的标记来填充已删除的对象,这样第二次delete或任何其他对指针的取消引用都会导致内存访问异常。 如果指针设置为NULLdelete将默默地忽略它,隐藏错误。

#3楼 票数:1

这个问题真的是基于意见的,所以我会提供一些意见......但也是这些意见的理由,希望这比意见本身对学习更有用。

  1. 在遗留代码中删除后使用 NULL 而没有任何智能指针来防止悬空指针总是明智的吗? (排除遗留代码的不良设计架构)

简短的回答:没有。

通常建议尽可能避免使用原始指针。 无论您的代码声称符合哪种 C++ 标准。

即使您以某种方式发现自己需要使用原始指针,确保指针在不再需要时不再存在,而不是将其设置为 NULL 更安全。 这可以通过作用域来实现(例如,指针对作用域来说是局部的,并且该作用域在delete pointer之后立即结束——这绝对阻止了该指针的后续使用)。 如果不再需要时无法使用指针,则不会意外使用它 - 并且不需要将其设置为NULL 这也适用于作为类成员的指针,因为当包含对象存在时,即在析构函数完成后,指针将不再存在。

“在不再需要时将指针设置为 NULL,并在使用前检查 NULL”的习语并不能防止愚蠢的错误。 作为一个粗略的规则,任何要求程序员记住做某事的习惯用法——例如将指针设置为 NULL,或将指针与 NULL 进行比较——都容易受到程序员错误的影响(忘记做他们需要做的事情)。

  1. 它在析构函数中也有意义吗?

一般来说,没有。 一旦析构函数完成,指针(假设它是类的成员)也将不复存在。 在它停止存在之前立即将其设置为 NULL 没有任何效果。

如果您有一个带有析构函数的类,由于某种原因,它与其他对象共享指针(即指针的值仍然有效,并且大概它指向的对象在析构函数完成后仍然存在),那么答案可能是不同的。 但这是一个极其罕见的用例——通常最好避免这种用例,因为管理指针或它指向的对象的生命周期变得更加困难——因此更容易引入晦涩的错误。 完成后将指针设置为NULL通常不是解决此类错误的方法。

  1. 在 getter 中,在第二步中测试 NULL 是否有意义? 或者无论如何它是未定义的行为?

显然,这取决于指针是如何初始化的。 如果指针未初始化,即使将其与NULL进行比较也会给出未定义的行为。

一般来说,我不会这样做。 大概会有一些初始化指针的代码。 如果该代码不能适当地初始化一个指针,那么代码应该以防止您的函数被调用的方式处理问题。 示例可能包括抛出异常、终止程序执行。 这允许您的函数安全地假设指针指向有效对象。

  1. 作为替代方案,这种形式主义又如何呢? 在什么情况下会崩溃?

“形式主义”与前一种相同——实际上区别在于文体。 在这两种情况下,如果m_var未初始化,则访问其值会产生未定义的行为。 否则,函数的行为是明确定义的。

在任何情况下都不能保证崩溃。 导致崩溃不需要未定义的行为。

如果调用者表现出未定义的行为(例如,如果您的函数返回NULL则调用者无论如何都会取消引用它),您的函数无法阻止这种情况发生。

#4楼 票数:0

您描述的情况仍然相对简单,因为变量是在局部作用域中描述的。
但是看看这个场景的例子:

struct MyObject
{
public :
    MyObject (int i){ m_piVal = new int(i); };
    ~MyObject (){ 
        delete m_piVal;
    };

public:
    static int *m_piVal;
};
int* MyObject::m_piVal = NULL;

写这个你可能会遇到双重释放问题:

MyObject *pObj1 = new MyObject(1);
MyObject *pObj2 = new MyObject(2);
//...........
delete pObj1;
delete pObj2; // You will have double Free on static pointer (m_piVal)

或者在这里:

struct MyObject2
{
public :
    MyObject2 (int i){ m_piVal = new int(i); };
    ~MyObject2 (){ 
        delete m_piVal;
    };

public:
    int *m_piVal;
};  

当你写这个时:

MyObject2 Obj3 (3);
MyObject2 Obj4 = Obj3; 

在销毁时,您将在这里获得 double Free 因为 Obj3.m_piVal = Obj4.m_piVal

所以有些情况需要特别注意(Implement : smart pointer, copy constructor, ... )来管理指针

  ask by TauCeti translate from so

未解决问题?本站智能推荐:

3回复

删除C++中的悬空指针

在此代码之后_var2是悬空Dangling pointer 。 我必须删除_var2( delete _var2 )吗? 这是不可避免的吗?
1回复

为什么我的指针在C++中变成悬空指针?

我的主要语言是 C#,我正在学习具有稀缺 C++ 背景的 opengl。// readShaderSource returns const string// no warningauto vShaderStr = readShaderSource("vshader.glsl");auto vShad
4回复

澄清C/C++中的悬空指针

我对C / C ++中的悬空指针有点困惑 我假设在功能remove()终止之前, Node* pt仍然是悬空指针? 我不必担心remove()终止后的指针Node* pt吗?
2回复

C++中的悬空指针和Delete命令

我在C ++代码中发现了一些非常奇怪的东西。 我以为delete会从堆中删除内存,而b->doIt()会失败。 但是在运行此代码时,它可以工作,甚至可以打印“ hello”。 为什么?
1回复

空悬空指针C++

我有一个指向抽象类对象ptr1的指针。 我需要创建另一个具有相同地址ptr2指针,以便在释放ptr1指针并将其清零时, ptr2也变为零。 我知道这是悬而未决的指针问题,可以使用智能指针解决,但我想在没有它们的情况下解决它。 在此先感谢您的帮助!
4回复

C++悬空指针和内存泄漏

我很难理解如何分辨悬空指针和内存泄漏。 关于最近的任务令我感到困惑,我有几个问题,在阅读之后,我仍然感到困惑。 我不希望有人为我做我的作业,我希望能够理解为什么它是什么,如果这是有道理的。 所以,作业: 鉴于声明: int *ptrA, *ptrB; 判断下面的每个代码段是否导致内
1回复

C++悬空指针/深层复制/浅层复制混乱

我听说当我们将相同的地址分配给两个不同的指针时,就会出现悬空指针问题。 这是由于两个指针都指向相同的内存位置,并且如果使用一个指针中的地址释放了内存; 它仍然可以从第二个指针访问(甚至从第一个指针访问,如果未设置为null,则我不在讨论这种情况)。 在下面的代码中,我尝试了不同的场景,在
5回复

在没有悬空指针的情况下在C++中返回抽象数据类型

你好, 我来自C#背景,没有很多C ++经验。 为了生成干净的代码,我尝试将实现和接口分开并尽可能使用继承。 当我尝试将典型的C#概念应用于C ++时,我遇到了一个迄今为止我无法解决的问题。 我认为对于经验丰富的C ++程序员来说这可能是微不足道的,但它已经让我疯狂了很长一段时间。