0

I've got the following function:

MyFunction(const char *value, bool trigger) {
    if (trigger) {
        std::string temporaryString = getTemporaryStringFromSomewhereElse();
        value = temporaryString.c_str();
    }
    // do processing here
    // I need `value` and `temporaryString.c_str();` to be alive and accessible here and not destroyed
 
    MyClass *object = new MyClass(value);
    object->Work();
    // etc..

}

So, the question is, how can I "prolong" the lifecycle of the temporaryString outside of the scope of the if-clause?

Currently, I'm getting the following error:

Using pointer to local variable 'temporary' that is out of scope.

I understand this is related to the memory management, and the fact that the temporary is assumed to be "destroyed" or cleared from the memory after the if-clause. But I need to either prolong its life cycle, or to create another string (copy) which will have a different, wider scope.

How can I achieve this?

Requirements:

  1. Function signature cannot change, it should remain: MyFunction(const char *value, bool trigger)
  2. I use the value later on to initialize another object, do some other work. I cannot have 2 variables, e.g. value and anotherValueToBeUsedIfTriggerIsTrue.
17
  • 5
    Why not simply define your string before the block and set the value inside the block? Commented Nov 4, 2021 at 16:14
  • Is there an option to completely get rid of the temporaryString and assign to the vaule directly? Commented Nov 4, 2021 at 16:15
  • If you need the information "was set inside the block" you also can use std::optional. This is the most readable kind of code for my point of view Commented Nov 4, 2021 at 16:15
  • That sounds interesting, could you please modify my example to show how to use it? In practice, I just need to set the value to a new one, that's it. And it should be accessible outside of the block of course. Commented Nov 4, 2021 at 16:18
  • 1
    Take a look at the changes in my answer... Commented Nov 4, 2021 at 16:51

3 Answers 3

1

Simply move the declaration of the std::string out of the if block, up into the function block, eg:

MyFunction(const char *value, bool trigger) {
    std::string temporaryString;

    if (trigger) {
        temporaryString = getTemporaryStringFromSomewhereElse();
        value = temporaryString.c_str();
    }

    // do processing here
 
    MyClass *object = new MyClass(value);
    object->Work();
    // etc..

}

The std::string will be blank initially, and destroyed when the function exits, and as such the reassigned value will remain valid while the function is running, as long as temporaryString is not modified.

Sign up to request clarification or add additional context in comments.

1 Comment

I ended up with this solution
1

static storage is probably what you are searching for. static attribute to a variable extends its life time to the whole program execution time.

void MyFunction(const char *value, bool trigger) {
    if (trigger) {
        static std::string s_buffer; // Note : this line is executed only once so don't assign the value here
        s_buffer = getTemporaryStringFromSomewhereElse();
        value = s_buffer.c_str();
    }
    // use of value is still correct even outside the if statement.
}

Note : in case of multi threading programs use of static isn't thread safe, for this porpose the standard provides thread_local storage.

2 Comments

Will static std::string s_buffer; be deallocated once MyFunction returns?
@RichardTopchii no, that is the whole point. Being in static storage, the string will exist for the remainder of the program's lifetime. Every call to MyFunction will operate on the same string object. This is also why the code is not thread-safe, if multiple threads call MyFunction() at the same time
1

I prefer std::optional in that case as it also shows if the requested object was set or not.

Example:

std::string getTemporaryStringFromSomewhereElse()
{
    return "Here I am";
}

std::optional< std::string > MyFunction(bool trigger) {
    if (trigger) {
        return getTemporaryStringFromSomewhereElse();
    }   

    return std::nullopt;
}

int main()
{
    auto retval = MyFunction( true );
    if ( retval )
    {   
        std::cout << *retval << std::endl;
    }   
}

EDIT: ( After we got the info that the interface is not changeable )

This ends up in the question of ownership!

Who will allocate the memory of the passed string and who is responsible to free that memory.

Options:

  1. Allocate enough space and pass the pointer to that memory to the function and copy the content if trigger is set or set first char of memory to zero to show you pass back an empty string. If also an empty string is possible, use e.g. the first or last memory element as flag.
  2. Allocate the memory inside the function and copy the given string and pass back the pointer or return nullptr if trigger was not set. Caller of the function must deal with freeing the given memory.
  3. If it is guaranteed that the function will not be called again between the first call and the usage of the content, the function itself can keep a static array and pass back the address to that static memory.

BTW: Keeping broken interfaces is a good start point for bad software :-) In the given case if also empty strings are valid, you start hacking with flags in arrays and all that broken stuff ( normally we should use structs with flags in it as already defined with std::optional ).

4 Comments

Please note, that the function signature cannot be changed. I need it to be MyFunction(const char *value, bool trigger)
@RichardTopchii This should be part of your question!
now it is, I've updated my question.
What would be the simplest / the most straightforward way to implement this? Looks like the option 1 is the easiest. The function won't be called again between the 1st call and the use of the content. So far, I've ended extracting temporaryString declaration outside of the if-clause scope and it seems to have solved the issue, although the code is not very elegant.

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.