9

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.

moala
  • 5,094
  • 9
  • 45
  • 66
  • 4
    While it's good to return const reference generally, i think you can more than get away with returning a QString by value if you need to. It's copy on write, very cheap to copy. – Johannes Schaub - litb Feb 28 '10 at 22:27

7 Answers7

8

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?

Ton van den Heuvel
  • 10,157
  • 6
  • 43
  • 82
3

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
    }
}
John Knoeller
  • 33,512
  • 4
  • 61
  • 92
  • In fact, that was the point, does it exist internally to Qt for that (I didn't find it), or does it exist another way of doing that without this static empty QString? – moala Feb 28 '10 at 21:36
  • 2
    I'm sure other ways, exist. But a static empty QString is a _good_ way to solve this problem. You shouldn't be trying to avoid it. – John Knoeller Feb 28 '10 at 21:39
2

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.

rohanpm
  • 4,264
  • 17
  • 16
0

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;
    }
}
Mathias Soeken
  • 1,293
  • 2
  • 8
  • 22
  • 1
    Does it not resolve into the following issue? http://stackoverflow.com/questions/667396/parameter-passed-by-const-reference-returned-by-const-reference – moala Feb 28 '10 at 21:37
  • It depends on how you use it, if you assign this function call to a `const QString&` it is dangerous, but if you assign it to a `QString` it doesn't. It works fine in my example. – Mathias Soeken Feb 28 '10 at 21:51
  • Then, when using the default return value, at the caller point, it becomes const QString& theId = getId(i, QString()); but the temporary QString will be destroyed, then the reference broken, isn't it? – moala Feb 28 '10 at 21:57
0

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.

stijn
  • 34,664
  • 13
  • 111
  • 163
  • 3
    default is a bad idea since it is a C++ keyword – Mathias Soeken Feb 28 '10 at 21:25
  • 1
    Even if it looks attractive, http://stackoverflow.com/questions/667396/parameter-passed-by-const-reference-returned-by-const-reference shows that it may be bad... – moala Feb 28 '10 at 21:29
0

Would QString::null suffice?

blarf
  • 101
  • 2
  • Qt 4.6.2 is missing such static member of the `QString`, by some reason. But `QString::QString()` "constructs" the null string and I guess that constructor is something like `QString::PrivateData *private = QString::someStaticNullData` – ony Apr 30 '10 at 04:29
  • 1
    QString::null exists in my instance of Qt 4.6.2 (and, I expect, yours too). It's depreciated, but still there. If you're using a platform that uses ELF, Mach-O, or PE (Linux, *BSD, MacOS, Windows) files you should be able to use QString::null just fine. Embedded platforms probably have more restrictions. http://lists.trolltech.com/qt-interest/2005-11/msg01002.html – blarf Apr 30 '10 at 04:55
0

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.
DevSolar
  • 67,862
  • 21
  • 134
  • 209