简体   繁体   中英

string and const char* and .c_str()?

I'm getting a weird problem and I want to know why it behaves like that. I have a class in which there is a member function that returns std::string . My goal to convert this string to const char* , so I did the following

    const char* c;
    c = robot.pose_Str().c_str();  // is this safe??????
    udp_slave.sendData(c);

The problem is I'm getting a weird character in Master side. However, if I do the following

    const char* c;
    std::string data(robot.pose_Str());
    c = data.c_str();
    udp_slave.sendData(c);

I'm getting what I'm expecting. My question is what is the difference between the two aforementioned methods?

It's a matter of pointing to a temporary. If you return by value but don't store the string , it disappears by the next sequence point (the semicolon).

If you store it in a variable, then the pointer is pointing to something that actually exists for the duration of your udp send

Consider the following:

int f() { return 2; }


int*p = &f();

Now that seems silly on its face, doesn't it? You are pointing at a value that is being copied back from f . You have no idea how long it's going to live.

Your string is the same way.

.c_str() returns the the address of the char const* by value, which means it gets a copy of the pointer. But after that, the actual character array that it points to is destroyed. That is why you get garbage. In the latter case you are creating a new string with that character array by copying the characters from actual location. In this case although the actual character array is destroyed, the copy remains in the string object.

You can't use the data pointed to by c_str() past the lifetime of the std::string object from whence it came. Sometimes it's not clear what the lifetime is, such as the code below. The solution is also shown:

#include <string>
#include <cstddef>
#include <cstring>

std::string foo() { return "hello"; }

char *
make_copy(const char *s) {
    std::size_t sz = std::strlen(s);
    char *p = new char[sz];
    std::strcpy(p, s);
    return p;
}

int
main() {
    const char *p1 = foo().c_str(); // Whoops, can't use p1 after this statement.
    const char *p2 = make_copy(foo().c_str()); // Okay, but you have to delete [] when done.
}

From c_str() :

The pointer obtained from c_str() may be invalidated by:

  • Passing a non-const reference to the string to any standard library function, or
  • Calling non-const member functions on the string, excluding operator[], at(), front(), back(), begin(), rbegin(), end() and rend().

Which means that, if the string returned by robot.pose_Str() is destroyed or changed by any non-const function, the pointer to the string will be invalidated. Since you may be returning a temporary copy to from robot.pose_Str() , the return of c_str() on it shall be invalid right after that call.

Yet, if you return a reference to the inner string you may be holding, instead of a temporary copy, you can either:

  • be sure it is going to work, in case your function udp_send is synchronous;
  • or rely on an invalid pointer, and thus experience undefined behavior if udp_send may finish after some possible modification on the inner contents of the original string.

Q

const char* c;
c = robot.pose_Str().c_str();  // is this safe??????
udp_slave.sendData(c);

A

This is potentially unsafe. It depends on what robot.pose_Str() returns. If the life of the returned std::string is longer than the life of c , then it is safe. Otherwise, it is not.

You are storing an address in c that is going to be invalid right after the statement is finished executing.

std::string s = robot.pose_Str();
const char* c = s.c_str();  // This is safe
udp_slave.sendData(c);

Here, you are storing an address in c that will be valid unit you get out of the scope in which s and c are defined.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM