views:

459

answers:

7

Hi, 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.

+2  A: 

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
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
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
A: 

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;
    }
}
Rupert Jones
Does it not resolve into the following issue? http://stackoverflow.com/questions/667396/parameter-passed-by-const-reference-returned-by-const-reference
moala
Rupert Jones
Then, when using the default return value, at the caller point, it becomes const QString but the temporary QString will be destroyed, then the reference broken, isn't it?
moala
A: 

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
default is a bad idea since it is a C++ keyword
Rupert Jones
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
+3  A: 

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 {
    static const QString emptyString;

    if (i < myArraySize && (myArray[i] != 0)) {
        return myArray[i]->id; // id is a QString
    } else {
        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
No I'm not, it was for conciseness.
moala
+1  A: 

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.

Intransigent Parsnip
A: 

Would QString::null suffice?

blarf
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
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
Indeed, I have it with remark compatibility: `struct Null { };` `static const Null null;` `inline QString(const Null }`Which is equal to `inline QString::QString() : d( }`, but with difference that it can disappear in future. So fi you use _crossplatform_ library should consider that carefully.
ony
A: 

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