0
const char* getOutPath() 
{
  return classVarStr.c_str();
}

I have the previous function,

there is something weird when I receive the returned value,

I get the full path but not including the first character!

so if the path is results/appName_subStr.dat I get esults/appName_subStr.dat !

I changed the function call to

string getOutPath() 
{
  return classVarStr;
}

then I call c_str() after receiving the value to get the path correct with the first char

I was guessing that it could be happening because of the function stack pop could have modified the address somehow?

anyone faced similar problem, and what could have been the cause?

EDIT:

class X
{
private:
    string classVarStr;
public:
    X(string in) : classVarStr(in)
    const char* getOutPath() 
    {
      return classVarStr.c_str();
    }
    string getOutPathStr() 
    {
      return classVarStr;
    }
}

class B
{
private:
    X xinstance;
public:
    B(int argc, char * argv[])
    {
         getSomepathFn(argc, argv);
    }

    string getAppPath1() 
    {
        return xinstance.getOutPath(); // this create a string then pass a copy, and internally deleted
    }
    const char * getAppPath2() 
    {
        return xinstance.getOutPathStr().c_str();// this is a problem, create a string, then pass const to the data, and deleted before the function call return, **Undefined behaviour** because the `getOutPathStr()` doesnt return a const reference
    }

}

class appObj
{
     void printMessage()
     {
         B obj = getBObj();
         FILE *fileptr = fopen(obj->getAppPath2(), "a");// this is the faulty area
     }
};
aah134
  • 860
  • 12
  • 25

2 Answers2

3

In case your function uses std::string with automatic storage duration, returning a pointer to its internal storage will yield undefined behavior since the object is automatically destructed once the execution goes out of scope (the memory where the actual characters resided is freed as well):

const char* getOutPath() 
{
    std::string classVarStr;
    ...
    return classVarStr.c_str();
}

That's the reason why the same code that returns a copy of local std::string object (by value) works as expected.


This code (from your edit):

const char * getAppPath2() 
{
    return xinstance.getOutPathStr().c_str();
}

calls getOutPathStr() that returns std::string object by value, which means that inside the getAppPath2() method, there is a copy of this std::string object. But this copy exists only within this scope as well, it is equivalent to:

const char * getAppPath2() 
{
    std::string copy = xinstance.getOutPathStr();
    return copy.c_str();
}

which is exactly the case that I have described at the beginning ~> the cause of UB.

LihO
  • 41,190
  • 11
  • 99
  • 167
  • Who is downvoting us? I think your response might be helpful. I've deleted mine in disgust. Have a +1 – doctorlove Oct 01 '13 at 15:57
  • @doctorlove: I don't know but the downvote from my answer was removed already. You shouldn't delete your answer just because someone downvotes you with no explanation. – LihO Oct 01 '13 at 16:05
  • 1
    it is not, string is a private member of the class, and the class is available during the whole app life time, I will show more code – aah134 Oct 01 '13 at 17:01
  • I got the issue, the function call return a newly created string, which I didnt notice because it was passed back by value, NOT a const string & getString() – aah134 Oct 01 '13 at 18:22
  • i was confused because I had three layers of classes – aah134 Oct 02 '13 at 15:38
1

The char pointer returned by c_str() is only valid while classVarStr is exists or is unchanged. See here If you have done anything after that call which changes the string, the char array will change.
The second version copies the string so is much safer.

Community
  • 1
  • 1
doctorlove
  • 18,872
  • 2
  • 46
  • 62
  • it could be the issue, however I am trying to reintroduce the issue, to find out what caused it, up-voted to make it 0 :D – aah134 Oct 01 '13 at 18:06