【问题标题】:c++ pointers to objects type checkingc++ 指向对象类型检查的指针
【发布时间】:2011-05-04 19:30:18
【问题描述】:

如何验证指针指向的对象是否有效

相关代码

LookupTable<Product *> table;
Product temp = *table[selection];
// if *table[selection] is not a product, program crashes...

下面是查找表:

#ifndef LOOKUPTABLE_H
#define LOOKUPTABLE_H

#include <iostream>
#include <string>

using namespace std;

#define MAXRANGE 10

template <class T>
class LookupTable
{
private:
    T *aptr[MAXRANGE];
    int rangeStart[MAXRANGE];
    int rangeEnd[MAXRANGE];
    int numRanges;

public:
    T defaultValue;
    bool failedRangeCheck;
    std::string failReason;


    // Constructor
    LookupTable() 
    {   
        numRanges = 0; 
        defaultValue = T();
    }      

    void addRange(int start, int end)
    {
        std::cout << "Created a new range...  Start: " << start << " / End: " << end << endl;
        failedRangeCheck = false;

        //lines omitted because not working anyway

        if ( !failedRangeCheck )
        {
            //set ranges
            rangeStart[numRanges] = start;
            rangeEnd[numRanges] = end;

            //build new generic array with end-start+1 positions
            //set pointer to point to it
            aptr[numRanges] = new T[ end - start + 1 ];
            numRanges++;
        }
        else
        {
            std::cout << "Range overlapped another range." << endl;
            std::cout << failReason << endl;
        }
    }

    T &operator[](int value)     // Overloaded [] operator
    {
        for ( int i = 0; i < numRanges; i++ )
        {
            if ( (value >= rangeStart[i]) && (value <= rangeEnd[i]) )
            {
                return aptr[i][value - rangeStart[i]];
            }
        }

        return defaultValue;
    }

    ~LookupTable()
    {
         delete[] aptr;
         numRanges = 0;     
    }

};
#endif

【问题讨论】:

  • 为什么它不是一个产品? C++ 是静态类型的,不像 python
  • @aaa:这很好。我(我猜所有其他回答的人)都误读了,并认为这里发生了一些多态性。但显然不是……
  • 不是不包含产品,而是产品对象可能还没有插入到那个位置
  • @Justin:那你做错了。你试图做的太多了。要么创建一个实现查找表的类,要么使用实现它的类。不要同时使用和实施它。为每个人提供更大的图景,以便他们向您展示如何操作。
  • @JustinY17:您应该将未使用的元素设置为NULL

标签: c++ class pointers types object


【解决方案1】:

table 是一个LookupTable&lt;Product*&gt;。为什么它会包含一个不是Product*的指针?这没有任何意义。

您永远不需要这样做。您需要这样做的唯一原因是:

  • 通过一些复杂的转换,您将一个指向不是Product 的指针插入到table 中。唯一的解决办法是“不要那样做”。

  • 您有一个指向 Product 对象的指针,但是您搞砸了对象生命周期管理,并且在完成之前销毁了该对象。对此的解决方案是使用范围绑定的资源管理(SBRM,也称为资源获取是初始化,或 RAII),它允许自动管理生命周期。使用像shared_ptr/weak_ptr 这样的智能指针容器来促进这一点。

  • 您将空指针放入table。在这种情况下,您可以不将空指针放入查找表中,也可以在从表中获取指针后检查它是否为空。

【讨论】:

  • 我想我的问题更多的是如何检查指针是否为空?
  • @JustinY17:if (!p) { /* p is null */ }。我可以推荐a good introductory C++ book?
【解决方案2】:

根据你发在subsequent questionLookupTable的代码,这个问题终于可以回答了。 (真的,我认为您应该将代码放在这里并删除另一个问题。)

table[selection] 要么返回对表中条目的引用(如果找到选择),要么返回对默认初始化对象的引用。当 LookupTable 专门用于指针类型(例如代码中的 Product*)时,默认初始化的对象将是 NULL 指针。

因此,对于代码中的 LookupTable&lt;Product*&gt;,表达式 table[selection] 要么将结果作为指向在表中找到的 Product 的指针,要么返回 NULL Product 指针。

因此,您不应立即取消引用 table[selection] 的结果并尝试将其分配给 Product 对象,而应实际获取指针值并检查它。

这将通过类似于以下的代码来完成:

Product* result = table[selection];
if(result != NULL)
{
    Product temp = *result;
    // do something with temp, etc, etc
}
else
{
    cout << "invalid product code" << endl;
}

【讨论】:

  • 我现在在我的代码中实现了这个实现,但是当用户输入指向空产品指针的产品代码时,我仍然崩溃
  • table[selection] 在这种情况下实际上是否按预期返回了一个 NULL 指针?它实际上在哪一行代码上崩溃?如果没有更多信息,我很难猜测可能出了什么问题。
【解决方案3】:

你可以使用dynamic_cast:

if (dynamic_cast<Product *>(table[selection])) != NULL)
{
    ...
}

但是不要这样做。如果您发现自己需要根据对象的运行时类型采取特定操作,那么您几乎可以肯定做错了什么。这就是虚函数的用途。

【讨论】:

    【解决方案4】:

    听起来你需要dynamic_cast。但你的设计听起来也很可疑。为什么您的收藏不包含正确的类型?或者,如果您需要根据对象的类型做出决定,那么您很可能需要某种形式的多态性。

    【讨论】:

      【解决方案5】:

      您可以使用 RTTI。包括 &lt;typeinfo&gt; 标头,然后说:

      if (typeid(*table[selection]) == typeid(Product)) { ... }
      

      但是这里有些东西真的很可疑......上面的陈述基本上是同义反复的,你根本不需要这样做。 C++ 是一种强类型语言,因此根据定义,包含在Product 对象容器中的任何对象都是Product 的实例——除非你做了一些荒谬的事情,比如使用@987654325 将无效对象插入容器中@。

      【讨论】:

      • 不是无效,只是可能还没有启动。
      • 您似乎对类型系统有一个基本的误解。它是否“启动”并不重要(您的意思是初始化/构造?) - 它仍然是 Product 类型的指针
      • 如果table[selection] == NULL,那么typeid会抛出异常。如果尚未初始化,则会出现未定义的行为...
      • 我明白你在说什么,那我怎么看它是否已经初始化了
      • 你无法判断一个特定的指针是否指向一个初始化的对象,只给定指针本身。但是你为什么要首先将未初始化的指针插入到容器中呢?
      【解决方案6】:
      Product * temp = dynamic_cast<Product*>(table[selection]);
      if (temp) {
         do something
      }
      

      并继续执行此操作。人们会告诉你不要这样做,但不要听他们的。

      【讨论】:

      • -1 纯粹是为了建议“继续这样做”。也许这是开玩笑的意思,但除此之外,这绝对是个糟糕的建议!
      • @Oli:我认为要求解释和辩论优点是更好的一般政策,而不是立即假设您比海报更了解。在这种特殊情况下,您自己的答案提倡胖接口,它有自己的问题(请参阅 TC++PL3),如果缺乏理由,任何“做一个而不是另一个”的断言都没有多大价值。
      • @Tony: dynamic_cast 可以解决眼前的、短期的问题。但总的来说,它会导致问题,并表明存在大量设计问题。提倡将其作为合理的解决方案根本不合适。我的回答不具体;除此之外,虚函数是执行运行时多态性的方法。 (事实证明,这对提问者也无济于事,但他们的问题并不清楚。)
      • @haters:有很多例子说明 dynamic_cast 很好:例如,一些库将 void* 指针指向“用户数据”,然后通过一些回调或将其作为 void* 返回某物。或者,也许我想要真正的异构数组。当人们说“你不想那样做”时,我很恼火——他们知道什么?有时我们确实需要这样做。意见很好,但人们只是对它发疯。
      猜你喜欢
      • 2023-02-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-27
      • 2014-03-18
      • 2019-10-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多