2

I have a function has a return type of std::string& and how do I return a NULL string& if no condition matches in the function?

std::string& SomeClass::getSomething()
{
     if(){...}
     else if(){...}
     // return a NULL
}
11
  • 9
    You can't. There is no such thing as a NULL std::string. You need to re-think your approach. Commented Mar 28, 2016 at 16:28
  • Maybe return an empty string? Commented Mar 28, 2016 at 16:29
  • You could return a pointer in stead of a reference, then you could return a NULL pointer. Commented Mar 28, 2016 at 16:30
  • 4
    What about throwing an exception? Commented Mar 28, 2016 at 16:31
  • 1
    The is also boost::optional Commented Mar 28, 2016 at 16:32

5 Answers 5

11

C++ references cannot be null.

If you are returning a reference to an object whose lifetime is not tied to the scope of the function call, like a data member, you can safely return a raw pointer (I would recommend a pointer to const).

std::string const* foo::bar() const {
    if (condition) {
        return &some_data_member;
    } else {
        return nullptr;
    }
}

If not, the best solution is to use a wrapper type like boost::optional (or std::optional in C++17). This not only allows you to return an optional object by value (which may be more performant), but is also self-documenting.

std::optional<std::string> foo::bar() const {
    if (condition) {
        return "hello, world";
    } else {
        return std::nullopt;
    }
}

Alternatively, you could return a pointer, which can be null. However, returning a raw pointer raises the question of who is responsible for deleting the dynamically allocated string. In this case, returning a std::unique_ptr would be the best option, as ownership is explicitly passed to the caller.

std::unique_ptr<std::string> foo::bar() const {
    if (condition) {
        return std::make_unique<std::string>("hello, world");
    } else {
        return nullptr;
    }
}

Or even simpler, you could return an empty string, if this is possible in your case. And honestly, this is my preferred approach (KISS).

std::string foo::bar() const {
    if (condition) {
        return "hello, world";
    } else {
        return "";
    }
}
Sign up to request clarification or add additional context in comments.

2 Comments

Given that in the original code, the returner owns the string being referred to, I think it would be fine to return a non-owning raw pointer. Returning a unique_ptr transfers ownership to the caller, which is a serious change in semantics WRT. the original code.
@juanchopanza Noted.
1

Anyway you wouldn't return NULL but nullptr. Also, you should be carefull with returning references from a function and make sure the reference referes to a valid, living object. returning reference to local object is wrong.

you can't return nullptr since nullptr is a pointer and string& is a reference - different types.

your options are:

  1. throw an exception
  2. use something like Optional classes (boost::optional, etc.)

personally, if I know there is a strong possibility the function may fail, I would pass the result to a reference type argument and return bool to indicate success of failure

bool SomeClass::getSomething(std::string& result)
{
     if(){result = "success 1"; return true; }
     else if(){result = "success 2"; return true; }
     return false.
}

3 Comments

The 1970s called...!
@BarryTheHatchet so when .Net gives you TryParse,TryGetValue it's cool and modern, but on C++ it's suddenly ancient and ugly?
When did I say TryParse and TryGetValue are "cool and modern"? (Hint: I didn't) (Another hint: those are ancient and ugly, too)
0

Returning the empty string '' might make sense here.

From your code fragment I'd be wondering if you are peeking under the covers of the class to make a decision that the class itself should be making. See the Martin Fowler's article about "Tell, don't Ask" which also refers to the original article on this by The Pragmatic Programmers.

Comments

0

As stated in comments by juanchopanza, you can't.

If you need to test for NULL you could re-think your approach using a smart pointer. For instance a std::shared_ptr<std::string>:

std::shared_ptr<std::string> SomeClass::getSomething()
{
     std::shared_ptr<std::string> stringPtr;
     if(){
         //...
         stringPtr = std::make_shared<std::string>("Whatever string goes here");
     }
     else if(){
         //...
         stringPtr = std::make_shared<std::string>("The other string...");
     }
     return stringPtr;
}

Then you could just test the std::shared_ptrwith its implicit conversion to bool:

auto strReturnedPtr = someClassObj.getSomething();
if (strReturnedPtr)
{
    // Do stuff
}

4 Comments

Do not use new, but stringPtr = make_shared ...
Why shared_ptr? The only participants in this seem to be the caller and getSomething, and getSometing is out of the game at hand-over to caller.
@DieterLücking noted. Couldn't fix it before, I was getting the "Ooops something went wrong" with SO, weird.
@user4581301 Just gave an example with the shared_ptr to show usage with smart pointers, don't know the OP context. I should have also mentioned unique_ptr as already proposed in another answer. Anyway in retrospective, a smart pointer seems overkill in this case.
0

I was facing the same issue. What I did was to let the caller pass what to return in case the return has to be null:

string myFunc(string param1, string not_found_value) {

if (not_returning_null)
    return actual_string;
else
    return not_found_value;

}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.