Question

consider the following code:

const QString& MyClass::getID(int index) const
{
    if (i < myArraySize && myArray[i]) {
        return myArray[i]->id; // id is a QString
    } else {
        return my_global_empty_qstring; // is a global empty QString
    }
}

How can I avoid to have an empty QString without changing the return type of the method? (It seems that returning an empty QString allocated on the stack is a bad idea)

Thanks.

Was it helpful?

Solution

You can't. Either do not return a const reference or use a local static variable like this:

const QString& MyClass::getID(int index) const {
    if (i < myArraySize && (myArray[i] != 0)) {
        return myArray[i]->id; // id is a QString
    }

    static const QString emptyString;
    return emptyString;
}

The advantage of this method over the other proposed methods is that this solution does not require a change to the interface of MyClass. Furthermore, using a default parameter might confuse users of your class and lead to wrong class usage. This solution is transparent to the user.

By the way, are you really using a C style array in your class?

OTHER TIPS

Since this is expected to return a const value I see no problem with having a global (or static const) empty QString that is used by all such functions to return a an empty string.

I'm not wild about the name though. I would expect that the "empty" QString would be a static const member of the QString Class. so your code would look like this instead.

const QString& MyClass::getID(int index) const
{
    if (i < myArraySize && myArray[i]) {
        return myArray[i]->id; // id is a QString
    } else {
        return QString::EmptyString; // is a global empty QString
    }
}

You can't avoid it without changing the return type.

If you choose to return a reference, then you must have some variable of the return type which outlives the function's scope. If you can't change the API (e.g. due to binary compatibility promises), then you are locked in to this forever. You'll have to waste memory storing some value of the relevant type, even if you change the rest of your class implementation to e.g. generate the values on the fly or retrieve them from some external source.

This is why C++ API design guides which are aware of binary compatibility issues recommend to not return a const& without careful consideration.

How about using a pre-initialized default value:

const QString& MyClass::getID(int index, const QString& def = QString()) const
{
    if (i < myArraySize && myArray[index]) {
        return myArray[index]->id; // id is a QString
    } else {
        return def;
    }
}

if you insist on returning a reference, you must have an object to refer to; so you must have the QString object somewhere in your example, there is no way around it.

However a technique that seems suitable for your case is to change your method to accept a default ID to return in case the index is out of range:

const QString& MyClass::getID( int i, const QString& default ) const
{
  if( i < myArraySize && myArray[i] )
    return myArray[i]->id;
  else
    return default;
}

You could also throw an exception if the index is out of range, then you wouldn't need to actually return on failure but that's probably not what you want.

Would QString::null suffice?

You cannot avoid the need for an empty QString without changing the way getId() works. But there are two approaches that spring to mind:

  • instead of silently returning an empty string, throw an exception; or
  • don't bother about returning a reference, and just return a QString, relying on return value optimization to eliminate the cost of copying the object.
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top