【问题标题】:If a pointer is set to NULL wouldn't any references to it or through it also be NULL如果指针设置为 NULL,则对它的任何引用或通过它的引用也不会为 NULL
【发布时间】:2012-12-05 22:04:05
【问题描述】:

如果一个指针被设置为 NULL,那么任何对它的引用或通过它的引用也不会是 NULL。这是一个可编译的示例,当您尝试运行它时会爆炸:

#include <string>
#include <iostream>

#define NULL 0

class Seedcoat {
public:
    //Seedcoat();
    std::string Name;
    int Weight;
};

class Seed {
public:
    //Seed();
    std::string Name;
    int Weight;
    Seedcoat* ItsSeedcoat;
};

class Apple {
public:
    //Apple();
    std::string Name;
    int Weight;
    Seed* ItsSeed;
};

int main()
{
///////Apple Objects Begin///////
    Apple       MyApple;
    Seed        MySeed;
    Seedcoat    MySeedCoat;

    MyApple.ItsSeed = &MySeed;
    MyApple.ItsSeed->ItsSeedcoat = &MySeedCoat;
    MyApple.ItsSeed->ItsSeedcoat->Weight = 2;

    if ( MyApple.ItsSeed != NULL) {
        std::cout << "The weight of the apple seed's seedcoat is " << MyApple.ItsSeed->ItsSeedcoat->Weight <<".\n";
    }

    MyApple.ItsSeed = NULL;

    if ( MyApple.ItsSeed->ItsSeedcoat != NULL) {
        std::cout << "The weight of the apple seed's seedcoat is " << MyApple.ItsSeed->ItsSeedcoat->Weight <<".\n";
    }

    return 0;
}

所以我的问题是:为什么会这样

MyApple.ItsSeed->ItsSeedcoat != NULL

返回真。我认为它不会因为 ItsSeed 设置为 NULL - 但它仍然尝试引用 ItsSeedcoat 的权重值 - 然后我认为它会爆炸,因为 ItsSeed 不存在。我意识到有一些简单的方法可以解决这个问题——这个例子只是为了展示我观察到的行为。这有什么好担心的吗? - 或者这是正常行为?这样做的原因是什么?谢谢。

【问题讨论】:

  • 除了给出的答案之外,您应该知道您没有将对象设置为 NULL。您只需将指针设置为 NULL。指针不是对象。指针只指向对象。当你给那个指针赋值时,它之前指向的对象根本不受影响。
  • 确实如此。我进行了编辑以澄清。
  • ItsSeed 当然存在。它是一个指针,它的值为 NULL。这意味着MyApple.ItsSeed == NULL。所以你实际上在做的是:NULL-&gt;ItsSeedcoat != NULL。显然这是一个 NULL 指针取消引用。 NULL 指针取消引用的通常结果是程序会崩溃。
  • 对,有效地址不再存在——不是指针本身。我认为人们(基于答案)理解我的意思 - 但随时编辑问题以使其更清楚。谢谢。

标签: c++ oop object null


【解决方案1】:

C++ 不会以这种方式握住你的手。将指针设置为 null 只会将该指针设置为 null。它不会像您在 Java 或 Python 中所期望的那样清除任何子对象或释放任何内存。

一旦将指针设置为 null,访问 MyApple.ItsSeed-&gt;ItsSeedcoat 就不再合法,因此任何事情都可能发生。

在您的特定问题中,我认为组合可能是一个更好的解决方案。但是,如果您确实需要在 C++ 中管理内存分配/释放,我强烈建议您使用适当的智能指针,它为您提供的功能与其他语言中的垃圾收集器大致相同。

我还建议不要自己定义 NULL,因为某些头文件已经为 C 定义了它。在 C++03 中,我通常建议使用文字 0,而在 C++11 中,您可以使用 nullptr 关键字.

【讨论】:

  • 就我目前的理解而言,这将需要我编写更多的 if 语句,以确保在我尝试做之前通过不存在的(null)父指针引用的所有内容都确实存在什么都有。
  • @Stepan1010 在 C++ 中,您通常会将您的代码设计为一开始就不需要需要这些检查。你给你的类一组不变量,然后你总是知道什么是可以安全访问的。有时你确实需要if 检查(例如在链表中)。
  • 不幸的是,我没有设计代码库——我只是在使用它。我重新了解了聚合(我认为这是我正在做的事情)和组合之间的区别。由于代码库的大多数函数都返回指针——我想我将不得不坚持聚合。但我想我也会研究智能指针(我假设是提升)。无论如何,不​​会有那么多 if 语句(大多数是非嵌套的)。我只是想保持代码干净。我很欣赏这种洞察力。我会调查他们。由于您提供了可能的替代方案,因此您获得了批准。谢谢。
【解决方案2】:

将MyApple.ItsSeed设置为NULL后,不允许取消引用指针MyApple.ItsSeed,即不允许使用表达式MyApple.ItsSeed-&gt;ItsSeedcoat。

这不一定会抛出异常,但它的行为是未定义的。

【讨论】:

    【解决方案3】:

    这是未定义的行为,任何事情都可能发生。

    特别是,

    MyApple.ItsSeed = NULL;
    if ( MyApple.ItsSeed->ItsSeedcoat != NULL)
    

    不允许取消引用 NULL 指针。就这么简单。如果这样做,则任何行为都是合规的。

    【讨论】:

      【解决方案4】:

      取消引用 NULL 指针会导致未定义的行为。为了访问成员 ItsSeedCoat,您必须取消引用指针 ItsSeed,您已经将其设置为 NULL。

      【讨论】:

        【解决方案5】:

        在您的示例中,您将作为 Seed* 的 MyApple.ItsSeed 设置为 NULL,然后在执行 MyApple.ItsSeed->ItsS​​eedcoat 时尝试取消引用 NULL 指针。

        【讨论】:

          【解决方案6】:

          将指针设置为空后,对该指针的任何引用 也是空的。但是,在您的代码中,您没有引用 指向指针;你有两个完全不同的指针对象, 你对一个人所做的对另一个人没有影响。 (这是 在我知道的每一种语言中都是如此。)

          【讨论】:

            【解决方案7】:

            C++ 没有实现您所描述的那种行为。在某些语言中,对象会跟踪指向它的所有“弱”指针,以便在释放该对象时,所有这些指针都会自动变为 NULL。然而,C++ 不是其中一种语言。当一个对象被释放时,没有指向该对象的指针会自动变为 NULL。当指向对象的特定指针被 NULL'ed 时,没有其他指向同一对象的指针自动被 NULL'ed。如果您需要这种行为,请查看boost::weak_ptr 或std::weak_ptr。

            【讨论】:

              猜你喜欢
              • 2013-08-21
              • 2016-05-09
              • 2023-03-28
              • 1970-01-01
              • 2017-01-29
              • 1970-01-01
              • 1970-01-01
              • 2011-10-06
              • 1970-01-01
              相关资源
              最近更新 更多