Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to "fill" a function argument, which defaults to null, with an object?

Say I have this method:

bool match( /* some optional parameter */ );

that will do some string pattern matching and I wanted to allow it to be given an optional parameter that will only be filled with an instance of a known type (Match) when the method match() returns true, would such a thing be possible?

In PHP I would be allowed to do:

public function match( Match &$match = null ) {
  if( someMatchingRoutineMatched() ) {
    $match = new Match();
    return true;
  }

  return false; // $match will stay null
}

And then call it like so:

// $test is some instance of the class that implements match()
// I don't have to declare $m up front, since it will be filled by reference
if( $test->match( $m ) ) {
  // $m would be filled with an instance of Match
}
else {
  // $m would be null
}

Is something similar possible in c++?

I have kind of gotten it to work with the following

bool match( Match*& match ) {
  if( /* something matches */ ) {
    match = new Match;
    return true;
  }

  return false;
}

... and then calling it like so:

Match* m = nullptr; // I wish I wouldn't have to declare this upfront as a nullptr
if( test.match( m ) ) {
  // a match occured, so m should no longer be a null pointer
  // but let's just make sure
  if( m != nullptr ) {
    // do something useful with m and afterwards delete it
    delete m;
  }
}

... however, this all feels a bit cumbersome. Furthermore I don't seem to be allowed to make the parameter optional like:

bool match( Match*& match = nullptr );

... since, I believe, references are not a allowed to be null, correct?

I hope you can see what I am trying to achieve and that you could give some insight in how I could go about achieving my goal, if it's at all possible to begin with, that is.

like image 489
Decent Dabbler Avatar asked Jan 06 '23 10:01

Decent Dabbler


1 Answers

invalid initialization of non-const reference of type 'Match*&' from an rvalue of type 'Match*'

Match*& match = nullptr is not allowed because references-to-non-const cannot bind to temporaries and passing nullptr here creates a temporary Match*.


You could return the pointer instead of passing a reference-to-non-const:

Match* match() {
  if( /* something matches */ ) {
    return new Match;
  }

  return nullptr;
}

Now a nullptr return value means no matches, and non-nullptr means that a match was found:

if( Match* m = test.match() ) { // nullptr means false, non-nullptr means true
  if( m != nullptr ) { // always true here
    // do something useful with m and afterwards delete it
    delete m;
  }
}

Or you could use overloading as @DanMašek mentioned:

bool match() {
  Match* m = nullptr;
  bool result = match(m);
  delete m; // deleting a nullptr is a no-op
  return result;
}

Last but definitely not least, mandatory use-unique_ptr-over-raw-owning-pointer, so you don't have to worry about delete, and it's clear without reading the documentation of match whether the returned pointer is owning or non-owning:

unique_ptr<Match> match() {
  if( /* something matches */ ) {
    return make_unique<Match>( /* constructor arguments */ );
  }

  return nullptr;
}

if( auto m = test.match() ) { // m deduced to be of type unique_ptr<Match>
  if( m != nullptr ) { // always true here
    // do something useful with m and afterwards delete it
    // no need to delete explicitly
  }
}
like image 138
emlai Avatar answered Jan 17 '23 17:01

emlai