我遇到了一个奇怪的问题,我想知道它为什么会这样。我有一个类,其中有一个返回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);
我得到了我期待的东西。我的问题是上述两种方法之间的区别是什么?
答案 0 :(得分:20)
这是指向临时的问题。
如果按值返回但不存储string
,则它会在下一个序列点(分号)消失。
如果将它存储在变量中,则指针指向udp发送期间实际存在的内容
请考虑以下事项:
int f() { return 2; }
int*p = &f();
现在看起来很傻,不是吗?您指向的是从f
复制回来的值。你不知道它会活多久。
您的string
也是一样。
答案 1 :(得分:6)
.c_str()
按值返回char const*
的地址,这意味着它获取指针的副本。但在那之后,它指向的实际字符数组将被销毁。这就是你得到垃圾的原因。在后一种情况下,您将通过从实际位置复制字符来创建具有该字符数组的新字符串。在这种情况下,虽然实际的字符数组被销毁,但副本仍保留在字符串对象中。
答案 2 :(得分:5)
在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.
}
答案 3 :(得分:5)
来自c_str():
从c_str()获得的指针可以通过以下方式无效:
- 将对字符串的非const引用传递给任何标准库函数,或
- 在字符串上调用非const成员函数,不包括operator [],at(),front(),back(),begin(),rbegin(),end()和 雷德()。
这意味着,如果robot.pose_Str()
返回的字符串被任何非const函数销毁或更改,则指向该字符串的指针将无效。由于您可能会从robot.pose_Str()
返回临时副本,因此c_str()
之后的udp_send
返回将在该呼叫之后无效。
然而,如果您返回对您可能持有的内部字符串的引用,而不是临时副本,您可以:
udp_send
同步; 答案 4 :(得分:3)
问强>
const char* c;
c = robot.pose_Str().c_str(); // is this safe??????
udp_slave.sendData(c);
<强> A 强>
这可能不安全。这取决于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
中存储一个地址,该地址将是您从s
和c
定义的范围之外的有效单位。