【问题标题】:making numerous pointers NULL at the same time同时使多个指针为NULL
【发布时间】:2009-06-19 23:24:30
【问题描述】:

这是我用 n 个指针创建的 C++ 类。

class SomeClass
{
private:
        int* ptr1;
        int* ptr2;
        ...
        int* ptrn;

private:
        // constructors, destructors, and methods
};

在初始化阶段,我想让所有这些指针都指向 NULL(或者在声明时让指针默认指向 NULL),而不是这样做:

void SomeClass::MakePtrNull()
{
        ptr1 = NULL;
        ptr2 = NULL;
        ...
        ptrn = NULL;
}

有没有什么简单的方法可以实现这个目标?我只是想知道是否有任何方法可以避免键入 n 行 ptr = NULL;在我的功能中。提前致谢。

添加基于我目前收到的答案: 不幸的是,这些指针必须分开,因为它们用于不同的目的。我这样命名指针只是为了说明我正在尝试做的事情,但每个指针都有完全不同的目的。我想我必须像我已经做的那样让它们指向 NULL。感谢您的回答。

【问题讨论】:

  • 请注意,如果类没有用户声明的构造函数, SomeClass() 将所有指针都为零。这意味着你可以这样做 *this = SomeClass();它会使所有指针都指向空指针。
  • @litb,在我的测试中,只有 SomeClass 的静态实例将所有指针都归零;自动和堆实例获取堆栈或堆中的任何内容。
  • 假设没有用户声明的构造函数,那么 SomeClass() 被初始化,而不是 { SomeClass a; 中的 "a" }。 SomeClass() 递归地对它的所有成员进行值初始化。这将使任何指针成员成为空指针。如果您定义了一个自动变量,并且它没有用户声明的构造函数,则它不会被初始化。例如,您必须这样做 { SomeClass a = SomeClass(); }
  • @litb:这是……非常晦涩难懂。因此非常容易忘记做、做错或让你的代码的普通读者感到困惑。
  • @CesarB,有些 C++ 行混淆了,有些则没有。如果有人对某事感到困惑,可以随时阅读一本好的 C++ 书籍,或询问其作者。当然我不会做“*this = MyClass();”在此示例中将其指针作为副作用无效。但我会像下面解释的那样做。

标签: c++ pointers


【解决方案1】:

创建一个类似智能指针的类而不是 int *,它的工作方式与 int * 完全相同,但默认构造为 NULL:

template <typename T>
class MyPointer {
    T *p;

public:
    MyPointer() : p(NULL) { }
    MyPointer(T *o) : p(o) { }
    operator T*() const { return p; }
    // ...and the rest of the traditional smart-pointer operators
};

然后,在你的课堂上使用它:

class SomeClass
{
private:
        MyPointer<int> ptr1;
        MyPointer<int> ptr2;
        ...
        MyPointer<int> ptrn;

private:
        // constructors, destructors, and methods
};

MyPointer&lt;int&gt; 类型的每个变量都将在SomeClass 的构造函数中自动正确初始化,无需任何额外的输入。如果您没有忘记或错误实现 MyPointer 的任何方法,它的行为将与普通指针完全一样,并且具有完全相同的大小和性能。

【讨论】:

  • +1 用于使用类型系统准确表达编程意图。
  • 另一个好处是您和代码维护者不需要在每个构造函数中初始化指针,或者记住在 MyPointer 成员的数量或名称发生变化时更新初始化列表。
【解决方案2】:

为什么不使用数组或向量而不是创建 n 个单独命名的指针?然后你可以在一个简短的 for 循环中进行归零。

【讨论】:

    【解决方案3】:

    你可以这样做:

    void SomeClass::MakePtrNull()
    {
            ptr1 = ptr2 = ptr3 = ... = ptrn = NULL;
    }
    

    【讨论】:

      【解决方案4】:

      首先,行不通的技术

      调用 memset 将整个对象设置为零是不行的。首先,如果你的函数有一个或多个虚函数会带来很多麻烦,其次,空指针不能保证用全零的位模式来表示。

      在您的情况下,我可能会做的是将指针存储在数组或向量中。 然后您可以使用std::fill 函数将它们全部设置为NULL。 (或者,如果您愿意,也可以使用循环)

      当然,如果您需要经常这样做,可能值得编写一个包装类,该类充当指针,但在其默认构造函数中将其设置为 NULL。

      或者你可以使用 boost::optional ,它的工作原理基本上是这样的。 (虽然不是专门针对指针的)

      【讨论】:

      • 您说空指针不能保证由全零的位模式呈现,这是否意味着这样的 if 检查: if(ptr1) 不是确定指针不为空?
      • 是的,请详细说明哪种情况 0x0 不是有效的“此处未分配内存”地址。此外,如果结构/类(以及它的父类)没有虚拟方法,那么它的 sizeof 将恰好是其成员的 sizeof 之和。
      • @average。那是安全的。 NULL ptr 必须评估为假,但实现可以在内存中表示它,但它喜欢它。实际上,几乎每个人都使用 0,因为 NULL ptr 也必须转换为整数作为 0,而且不更改位模式通常是最简单和最有效的。 @Shane:结构必须是POD,才能保证您所说的标准。除了虚拟方法之外,还有其他一些东西可以导致结构成为非 POD,并且拥有任何基类就是其中之一。
      • @Shane:没有太多要详细说明的地方。它通常遵循 CPU 架构。在某些机器上,地址 0 可能是有效地址,而另一个值通常用于“空”。或者在具有分段内存模型的机器上,“null”值也可能不是普通的 0x0。在大多数计算机上,零值和空指针的值之间没有区别,但在 C++-standard-land 中,为了可移植性,不保证是这种情况。
      • NULL 不是空指针。它是一个空指针常量,为 0。jalf 谈到一个空指针,它不是 0,而是一个不指向对象或函数的指针。它也不会转换回 0。转换只是从 0 一个空指针 - 但是它转换为带有 false 的 bool。有关差异的信息,请参阅stackoverflow.com/questions/651361/boolean-datatype-question/…
      【解决方案5】:

      如果您必须单独保留指针,我建议您执行以下操作(可能最迫切的需要是指针可以具有不同的类型)

      class SomeClass {
          struct Pointers {
              int* ptr1;
              int* ptr2;
              float* ptrn;
          } ptrs;
      
      public:
          void MakePtrNull();
      };
      
      void SomeClass::MakePtrNull()
      {
          // clears all pointers at once
          ptrs = Pointers();
      }
      

      这确实有效,因为没有用户声明构造函数的类的值初始化将对其所有成员进行值初始化。指针的值初始化将创建一个空指针。

      【讨论】:

        【解决方案6】:

        为什么不使用默认构造函数:

        SomeClass::SomeClass() : ptr1(NULL), ptr2(NULL), ...
        {
        
        }
        

        你也可以这样做:

        ptr1 = ptr2 = ptr3 = NULL;
        

        【讨论】:

          【解决方案7】:

          您可以将指针放入一个结构中,然后在需要时 memset() 该结构。指针仍然是分开的,但是您可以将它们作为一个单元来定位,而不会影响班级的其余部分。例如:

          struct MyPointers
          {
              int* ptr1;
              int* ptr2;
              ...
              int* ptrn;
          };
          
          class SomeClass
          {
          private:
              MyPointers ptrs;
              ...
          };
          
          void SomeClass::MakePtrNull()
          {
              memset(&ptrs, 0, sizeof(ptrs));
          }
          

          【讨论】:

            【解决方案8】:

            为此使用矢量(因为从它的声音来看,您将来不需要编辑列表 - 而且您需要随机访问)。你可以这样做:

            class PointerList
            {
            private:
                typedef std::vector<int*> IntPtrVector;
                IntPtrVector m_ptrVec;
            
            public:
                PointerList()
                {
                    m_ptrVec.reserve(5);
                    for (int i = 0; i < 5; i++)
                        m_ptrVec.push_back(NULL);
                }
            
                int* getPointer(int index)
                {
                    return m_ptrVec[index];
                }
            
                void setPointer(int index, int* ptr)
                {
                    assert(index <= 4);
                    m_ptrVec[index] = ptr;
                }
            };
            

            编辑

            说实话,这有点贫民窟的味道。您确定您的问题需要此解决方案吗?如果您详细说明您的具体问题,也许在另一个问题中,我相信您可以得到更好的答案,了解如何更优雅地完成您想要的事情 - 而不是通过创建第二个问题。

            【讨论】:

            • 问题的重点是问我是否可以采取一种懒惰的方式来解决问题。不过,感谢您抽出宝贵时间提出建议。
            猜你喜欢
            • 1970-01-01
            • 2023-03-28
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-08-24
            相关资源
            最近更新 更多