string and const char* and .c_str()?

string and const char* and .c_str()?

本文关键字:and str const char string      更新时间:2023-10-16

我遇到了一个奇怪的问题,我想知道为什么它会这样做。我有一个类,其中有一个成员函数返回std::string。我的目标是将这个string转换为const char*,因此我执行了以下操作

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

问题是我在Master这边得到了一个奇怪的角色。但是,如果我执行以下操作

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

我得到了我所期待的。我的问题是,上述两种方法有什么区别?

这是一个指向临时的问题。如果按值返回,但不存储string,它将在下一个序列点(分号)之前消失。

如果你把它存储在一个变量中,那么指针指向的是在你的udp发送期间实际存在的东西

考虑以下内容:

int f() { return 2; }

int*p = &f();

这看起来很傻,不是吗?您指向的是正在从f复制回来的值。你不知道它能活多久。

你的string也是这样。

.c_str()按值返回char const*的地址,这意味着它获得了指针的副本。但在那之后,它所指向的实际字符数组被销毁。这就是为什么你会得到垃圾。在后一种情况下,您将通过从实际位置复制字符来创建具有该字符数组的新字符串。在这种情况下,虽然实际的字符数组被销毁,但副本仍然保留在字符串对象中。

您不能使用c_str()所指向的超过std::string对象生命周期的数据。有时不清楚生命周期是什么,例如下面的代码。解决方案也给出了:

#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():

从c_str()中获得的指针可能会被以下方式无效:

  • 将字符串的非const引用传递给任何标准库函数,或者
  • 在字符串上调用非const成员函数,不包括操作符[]、at()、front()、back()、begin()、rbegin()、end()和撕裂()。

这意味着,如果robot.pose_Str()返回的字符串被销毁或被任何非const函数更改,指向该字符串的指针将失效。由于您可能会从robot.pose_Str()返回一个临时副本,因此在调用之后返回c_str()将是无效的。

但是,如果返回对可能持有的内部字符串的引用,而不是临时副本,则可以:

  • 确保它会工作,如果你的函数udp_send是同步的;
  • 或者依赖于一个无效的指针,如果udp_send可能在对原始字符串的内部内容进行一些可能的修改后完成,则会经历未定义的行为。

Q

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

这可能不安全。这取决于robot.pose_Str()返回什么。如果返回的std::string的寿命比c的寿命长,则它是安全的。

您在c中存储的地址在语句执行完成后将无效。

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

这里,您在c中存储了一个地址,该地址将在您离开sc定义的作用域时有效。