Find the answer to your Linux question:
Results 1 to 5 of 5
Hi, I Inherited the following code: Code: string IntToString(int nVal) { char sVal[254]; memset(sVal, 0, 253); sprintf(sVal, "%d", nVal); string strVal = sVal; return strVal; } I know that the ...
  1. #1
    Just Joined!
    Join Date
    Jul 2010
    Posts
    5

    Question C++ Local scope variable passed back. Issue?

    Hi,

    I Inherited the following code:

    Code:
    string IntToString(int nVal)
    {
       char sVal[254];
       memset(sVal, 0, 253);
       sprintf(sVal, "%d", nVal);
    
       string strVal = sVal;
       return strVal;
    }

    I know that the scope for strVal ends after the return happens. I also know that strVal is left on the stack and, as far as I know, this code works.

    According to the standards this code is violating scope rules.

    Now the big question; in a single threaded LINUX application, is this a major issue or not?

  2. #2
    Trusted Penguin Cabhan's Avatar
    Join Date
    Jan 2005
    Location
    Seattle, WA, USA
    Posts
    3,230
    What standards is this violating?

    I'm not a C++ expert, but I believe that in this instance, the code should work okay.

    The usual problem with returning local-scope variables is when you return pointers to variables that are deallocated at the end of the function:
    Code:
    char *foo(void) {
        char buf[1024];
        buf[0] = 'f';
        buf[1] = 'o';
        buf[2] = 'o';
        buf[3] = '\n';
    
        return buf;
    }
    This code will not work because the memory for buf is deallocated at the end of the function, but you are passing back a pointer. So the program will segfault once the pointer is accessed.

    The correct way around this is to allocate the memory for the buffer on the heap:
    Code:
    char *foo(void) {
        char *buf = malloc(1024);
        buf[0] = 'f';
        buf[1] = 'o';
        buf[2] = 'o';
        buf[3] = '\n';
    
        return buf;
    }
    In your instance, you are not returning a pointer, but a string object. Even though you have the buffer allocated on the stack like in the examples above, this line:
    Code:
    string strVal = sVal;
    is functionally equivalent to:
    Code:
    string strVal(sVal);
    which is to say, you are constructing a string object based on the buffer. So your code is not returning the array, but a string object that contains a copy of the array internally.

    Note that I am assuming that you are using the standard C++ std::string class. If you have done some sort of typedef char *string, then everything I said is wrong, and your code does in fact have an error.
    DISTRO=Arch
    Registered Linux User #388732

  3. #3
    Just Joined!
    Join Date
    Jul 2010
    Posts
    5
    My understanding was that anything declared in a method in C or C++ was placed on the stack and when the method returns, the pointers are restored.

    I know this was an issue in C because of interrupts. You could never be certain of the values on a stack because an interrupt could come around and wipe them out. I have first hand knowledge of this scenario. I assumed that this is also the case in C++.

  4. #4
    Linux Newbie tetsujin's Avatar
    Join Date
    Oct 2008
    Posts
    115
    Quote Originally Posted by leonm54 View Post
    My understanding was that anything declared in a method in C or C++ was placed on the stack and when the method returns, the pointers are restored.

    I know this was an issue in C because of interrupts. You could never be certain of the values on a stack because an interrupt could come around and wipe them out. I have first hand knowledge of this scenario. I assumed that this is also the case in C++.
    It is true that strVal is allocated on the stack, and it doesn't survive beyond its scope.

    However, you are returning a copy of strVal.

    More precisely - in the absence of relevant compiler optimizations (and as Cabhan said, assuming this is C++'s std::string and not some other string type), the statement "return strVal" creates a copy of strVal which survives beyond the function itself - long enough for something to be done with that copy. So if you were to call:

    Code:
    std::string a = IntToString(42);
    You would (naively) expect this to result in two std::string copy operations:
    • strVal being copied to IntToString()'s return value
    • return value being copied to (a).


    Note that those first two copies of the string (strVal and the return value) don't survive for long - but the string data survives because each time it is copied before the source copy is destroyed.

    (Compiler optimizations may streamline this a bit: recognizing that strVal is being returned (and therefore assigning straight into the return value copy, or even (a), instead of performing the two copies. Additionally, it's common for optimizations of std::string to share memory between copies of a string - so even if you did wind up copying the string twice and destroying two copies, you're not actually allocating additional copies of the string data or copying the characters within that buffer, you're just changing the value of the string's instance counter.)

    This is one of the things that makes C++ a bit nicer to work with than regular C: if you write your classes right, you can use the object's lifetime to nicely manage allocation and deallocation of the resources that object uses.

  5. #5
    Just Joined!
    Join Date
    Jul 2010
    Posts
    5

    Thumbs up Thank you.

    Many thanks to Cabhan and tetsujin.

    This is an eye opener for me. I really thought I had an issue here.

    Before posting, I attempted to look this up online and in the C++ programming language 3rd edition. If this scenario is documented, I did not find it. If anyone knows where this is documented, please let me know.

    Thanks again.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
...