0

How do I verify that an object being pointed by a pointer is valid

relevant code

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

Here is what Lookup table is:

#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
JuggernautDad
  • 1,135
  • 2
  • 13
  • 28

6 Answers6

3

table is a LookupTable<Product*>. Why would it contain a pointer that isn't a Product*? That doesn't make any sense.

You shouldn't ever need to do this. The only reasons you would need to do this are if:

  • Through some convoluted cast you inserted a pointer to something that isn't a Product into table. The only solution to this is "don't do that."

  • You have a pointer to what was a Product object, but you've screwed up your object lifetime management and you destroyed the object before you were done with it. The solution to this is to use scope-bound resource management (SBRM, also called Resource Acquisition is Initialization, or RAII), which allows lifetimes to be automatically managed. Use a smart pointer container like shared_ptr/weak_ptr to facilitate this.

  • You put a null pointer into the table. In this case, you can either just not put null pointers into the lookup table, or check whether a pointer is null after you obtain it from the table.

James McNellis
  • 348,265
  • 75
  • 913
  • 977
  • i guess my question was more of how can i check to see if the pointer is null or not? – JuggernautDad Nov 04 '10 at 00:11
  • 3
    @JustinY17: `if (!p) { /* p is null */ }`. May I recommend [a good introductory C++ book?](http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list) – James McNellis Nov 04 '10 at 00:12
1

Based on the code of LookupTable that you posted in a subsequent question, this question can finally be answered. (Really, I think you ought to just put that code here and remove the other question.)

table[selection] either returns a reference to an entry in the table (if the selection is found) or otherwise a reference to a default-initialized object. When LookupTable is specialized for a pointer type (such as the Product* in your code) then the default-initialized object will be a NULL pointer.

So, for the LookupTable<Product*> in your code, the expression table[selection] is either going the result in a pointer to a Product found within the table or else a NULL Product pointer.

Consequently, instead of immediately dereferencing the result of table[selection] and trying to assign it to a Product object, you should actually take the pointer value and examine it.

This would be accomplished with code similar to:

Product* result = table[selection];
if(result != NULL)
{
    Product temp = *result;
    // do something with temp, etc, etc
}
else
{
    cout << "invalid product code" << endl;
}
Community
  • 1
  • 1
TheUndeadFish
  • 8,058
  • 1
  • 23
  • 17
  • i have this implementation working in my code now, but i am still crashing when a user inputs product code that points to a null Product pointer – JuggernautDad Nov 04 '10 at 01:57
  • Is `table[selection]` actually returning a NULL pointer as expected in that case? What line of code is it actually crashing on? It's rather hard for me to guess what might be wrong without more information. – TheUndeadFish Nov 04 '10 at 02:08
0

You can use dynamic_cast:

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

But DON'T DO THIS. If you find yourself needing to take specific action based on the runtime type of an object, you're almost certainly doing something wrong. This is what virtual functions are for.

Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
0

It sounds like you need dynamic_cast. But your design also sounds suspect. Why would your collection not contain the right types ? Or, if you need to make decisions based upon the type of your object, then some form of polymorphism is what you'd most likely require.

Brian Agnew
  • 268,207
  • 37
  • 334
  • 440
0

You can use RTTI. Include the <typeinfo> header, and say:

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

But something is really fishy here... the above statement is basically tautological, and you shouldn't need to do this at all. C++ is a strongly typed language, and so any object contained in a container of Product objects is, by definition, an instance of Product - unless you did something ridiculous, like inserting an invalid object into the container using a reinterpret_cast.

Charles Salvia
  • 52,325
  • 13
  • 128
  • 140
  • its not that its invalid, it just might not have been initiated yet. – JuggernautDad Nov 04 '10 at 00:07
  • 2
    You seem to have a fundamental misunderstanding of the type system. It doesn't matter whether it's "initiated" (do you mean initialized/constructed?) - it's still a pointer of type `Product` – Charles Salvia Nov 04 '10 at 00:09
  • If `table[selection] == NULL`, then `typeid` will throw an exception. If it hasn't been initialised, then undefined behaviour will ensue... – Oliver Charlesworth Nov 04 '10 at 00:10
  • i see what you are saying now, so how do i see if it has been initialised – JuggernautDad Nov 04 '10 at 00:12
  • You can't tell if a particular pointer points to an initialized object, given only the pointer itself. But why would you be inserting uninitialized pointers into a container in the first place? – Charles Salvia Nov 04 '10 at 00:14
  • im not, i initialize the array, then add objects into it similar to a hash table. some slots could be used while the next 200 are not. how do i verify that the selection the user entered is valid/initialized? – JuggernautDad Nov 04 '10 at 00:17
  • You need some way to represent "unused" slots in the array. If you represent unused slots as null pointers, you can simply check if the pointer is null. Given a pointer `p`, you can just say `if (!p)` to check if it is null. – Charles Salvia Nov 04 '10 at 00:18
  • @Justin: Reading an uninitialized variable leads to undefined behavior. That's it. There's nothing you can do about it. If you need to be able to test for your own version of uninitialized, then you need to have a system to do that. Initializing all the pointers to null is one such system; a pointer value of null can be seen as "uninitialized". – GManNickG Nov 04 '10 at 00:19
  • @Charles Salvia & @GMan what is the syntax for defining LookupTable table; as null – JuggernautDad Nov 04 '10 at 00:21
  • @JustinY17: Which part of it do you not understand? Do you not know what `NULL` is? Do you not know how to assign something to a variable? Have you read the first few chapters of [a good introductory C++ book?](http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list) What part of this is confusing that we can help explain? – James McNellis Nov 04 '10 at 00:33
  • LookupTable table = NULL; yeilds error no suitable constructor exists to convert from "int" to "LookupTable" I understand what null is and i even understand why i am getting this error... i just dont know what the syntax is to correct it – JuggernautDad Nov 04 '10 at 00:53
  • @JustinY17, this depends on how your `LookupTable` stores the internal collection of pointers. I don't know what your `LookupTable` class is, so I can't tell you. But, for example, if you internally use an `std::vector`, you could initialize it to all nulls using the `resize` member function, like `vec.resize(100, 0)`, which would create 100 null pointers, or just use the vector's fill constructor to construct the vector with 100 null pointers. If you use an internal C-array to store the pointers, you could use `std::fill` or even `memset` to initialize the array to all nulls. – Charles Salvia Nov 04 '10 at 12:20
-2
Product * temp = dynamic_cast<Product*>(table[selection]);
if (temp) {
   do something
}

and GO AHEAD AND DO THIS. People will tell you not to, but don't listen to them.

Colin
  • 3,670
  • 1
  • 25
  • 36
  • 4
    -1 purely for the advice to "go ahead and do this". Perhaps this was meant in jest, but otherwise, this is absolutely terrible advice! – Oliver Charlesworth Nov 04 '10 at 00:02
  • @Oli: I think it a better general policy to ask for an explanation and debate the merits rather than immediately assume you know better than the poster. In this particular case, you're own answer advocates a fat interface, which has its own problems (see TC++PL3), and any assertion of "do one and not the other" is much less valuable if it lacks justification. – Tony Delroy Nov 04 '10 at 00:53
  • @Tony: `dynamic_cast` may fix the immediate, short-term problem. But in general, it leads to issues, and indicates massive design problems. Advocating it as a reasonable solution is simply not appropriate. My answer was non-specific; other than that virtual functions are the way to do runtime polymorphism. (As it turns out, this wouldn't help the questioner either, but their question wasn't clear.) – Oliver Charlesworth Nov 04 '10 at 08:13
  • @haters: There are plenty of examples where dynamic_cast is good: for example, some libraries take void* pointers to 'user-data', and then give it back as a void* through some callback or something. Or, maybe I want truly heterogeneous arrays. It's irritating to me when people say "you don't want to do that" - what do they know? Sometimes we do need to do that. Opinions are fine, but people just go nuts with it. – Colin Nov 04 '10 at 18:27