11

What would I want to use instead of NULL if I have an unassigned pair in C++?

As an example, suppose I have (pseudo)code like the following:

pair<int,int> bestPair; //Global variable

updateBestPair(vector<int> a, vector<int> b) {

    bestPair = NULL;

    for (/* loop through a and b */) {
        if (/* pair(a,b) is better than bestPair and better than some baseline */)
            bestPair = make_pair(a,b);
    }

    if (bestPair != NULL) //Found an acceptable best pair
        function(bestPair);
    else
        cout<<"No acceptable pairs found"<<endl;
}
user1634426
  • 563
  • 2
  • 5
  • 12

3 Answers3

8

Is there a NULL equivalent for pairs in C++?

No.

What would I want to use instead of NULL if I have an unassigned pair in C++?

Here are a few options:

  • you can use a pointer to a pair, which can be set to NULL; This is probably not the best solution (since you are clearly not requiring a pointer)

  • you can use a boost::optional<std::pair<int,int>>;

  • you can (and probably should) rewrite your code not to use a global variable.

  • you can restructure your control flow to avoid checking for a valid pair as a separate step:

    pair<int,int> bestPair; //Global variable
    
    updateBestPair(vector<int> a, vector<int> b) {
    
        // not needed
        // bestPair = NULL;
    
        //loop through a and b
        if (/* pair(a,b) is better than bestPair and ... */)
        {
            bestPair = make_pair(a,b);
            function(bestPair);
        }
        else
            cout<<"No acceptable pairs found"<<endl;
    }
    
  • you can choose an artificial value to represent "invalid pair value":

    // use as constant, wherever you used NULL before
    const auto invalid_pair = std::make_pair(
        std::numeric_limits<int>::max(),
        std::numeric_limits<int>::max());
    
  • you can use a boolean flag:

    pair<int,int> bestPair; //Global variable
    
    updateBestPair(vector<int> a, vector<int> b) {
    
        bool initialized = false;
    
        //loop through a and b
        if (/* pair(a,b) is better than bestPair and ... */)
        {
            bestPair = make_pair(a,b);
            initialized = true;
        }
    
        if(initialized)
            function(bestPair);
        else
            cout<<"No acceptable pairs found"<<endl;
    }
    
  • you can use a custom solution (similar to boost::optional wrapper or not)

utnapistim
  • 26,809
  • 3
  • 46
  • 82
  • Your first code suggestion leaves `bestPair` in an "invalid state" with no variable denoting that fact. Given that `bestPair` is a global variable, it is most likely used elsewhere; therefore, this suggestion is unlikely to be a feasible approach. The rest is all good :) – Lightness Races in Orbit Sep 24 '15 at 11:13
  • I assumed that the bestPair had a valid value before calling into `updateBestPair`, due to the function being named **update**BestPair, not **init**BestPair (my bad - I had no reasons to assume). – utnapistim Sep 24 '15 at 11:17
  • 1
    Thanks, these are all really good ideas! I think using boost::optional would be the cleanest method, and that using a boolean flag would be the easiest (though also the easiest to screw up later on). I can't use artificial values for this particular application since any pair values are acceptable, though that's the approach I usually prefer. And yeah, not using a global variable would be the best, but in this case that would require rewriting the whole framework, so that goes on a to-do list for whenever I do a major restructuring! – user1634426 Sep 24 '15 at 11:22
  • @utnapistim: Fair enough I suppose but I'd expect a function named **updateBestPair** that didn't update `bestPair` to tell me that somehow :P And I don't just mean with a console message. – Lightness Races in Orbit Sep 24 '15 at 11:40
  • @user1634426, the implementation of boost::optional is effectively the storage for an automatic storage variable of the given type, and a bool flag to specify if the value was initialized (and the code to keep them synchronized). – utnapistim Sep 24 '15 at 12:14
5

No. C++ objects cannot be "NULLed".

(Even pointers, which are objects, cannot be "NULLed"! This is confusing because their value may be set to a null pointer value, which we sometimes in the past obtained with a macro named NULL; however, this has never been the same as "NULLing" the pointer itself. Er, anyway…)

I recommend either boost::optional, or rethink the idea of having a global variable that can be "has a useful value" or "does not have a useful value". What's the point in it existing if it has no useful value?

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • Wow, the boost::optional package looks like exactly what I need! Thanks! As for why I need a global variable like this in the first place - I'm doing some particle physics analysis where I need to read in a ton of collision events. Sometimes I find a relevant electron collision parameter, and sometimes I'll have collisions that don't have enough good electrons. However, in the second case I can't just go to the next event. I have to do the analysis still, just marking down somewhere that I didn't find a good electron pair. – user1634426 Sep 24 '15 at 11:09
  • 1
    @user1634426: Alright. In the olden days I'd have done as Marius suggests, then; `boost::optional` is the quicker/atomic way to achieve that. – Lightness Races in Orbit Sep 24 '15 at 11:11
1

No, that is not possible. You could use an additional variable to indicate the validity of the pair (that you have a pair).

Marius Bancila
  • 16,053
  • 9
  • 49
  • 91
  • 2
    Thanks, that sounds like a good idea. I prefer a way not to have to use two variables for a single purpose (easy for the two to lose sync), but I guess sometimes it's the best solution. – user1634426 Sep 24 '15 at 11:14