Pot*_*ito 7 c++ string pointers casting c++11
我在C++中使用C库并编写了一个包装器.有一次,我需要将一个转换std::string为一个c风格的字符串.有一个带有函数的类,它返回一个字符串.如果字符串很短,则转换返回的字符串,否则不起作用.这是一个简单且简化的示例,说明了该问题:
#include <iostream>
#include <string>
class StringBox {
public:
std::string getString() const { return text_; }
StringBox(std::string text) : text_(text){};
private:
std::string text_;
};
int main(int argc, char **argv) {
const unsigned char *castString = NULL;
std::string someString = "I am a loooooooooooooooooong string"; // Won't work
// std::string someString = "hello"; // This one works
StringBox box(someString);
castString = (const unsigned char *)box.getString().c_str();
std::cout << "castString: " << castString << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
执行上面的文件将其打印到控制台:
castString:
而如果我交换评论someString,它会正确打印
castString:你好
这怎么可能?
tem*_*def 16
您正在调用c_str由getString()成员函数重新调整的临时字符串对象.返回的指针c_str()仅在原始字符串对象存在时才有效,因此在您指定的行的末尾最终castString是一个悬空指针.正式地,这会导致不确定的行为.
那么为什么这适用于短串呢?我怀疑你正在看到短字符串优化的影响,这是一种优化,对于字符串小于一定长度的字符串数据存储在字符串对象本身的字节内而不是堆中.返回的临时字符串可能存储在堆栈中,因此在清理时没有发生解除分配,指向过期字符串对象的指针仍然保留旧的字符串字节.这看起来与你所看到的一致,但它并不意味着你所做的是一个好主意.:-)
box.getString()是一个匿名的临时.c_str()仅对变量的长度有效.
所以在你的情况下,当你到达时,c_str()它会失效std::cout.读取指针内容的行为未定义.
(有趣的是,由于以不同的方式存储短字符串,短字符串的行为可能会有所std::string不同.)
当你按价值回归时
box.getString() 是暂时的等等
box.getString().c_str() 仅在表达式期间有效,然后它是一个悬空指针.
你可以解决这个问题
const std::string& getString() const { return text_; }
Run Code Online (Sandbox Code Playgroud)
box.getString()产生一个临时的.调用c_str()它会给你一个指向临时的指针.临时停止存在后立即停止,指针无效,悬空指针.
使用悬空指针是Undefined Behavior.
首先,你的代码的 UB 与字符串的长度无关:
castString = (const unsigned char *)box.getString().c_str();
Run Code Online (Sandbox Code Playgroud)
返回的字符串getString被破坏,并且castString是指向被破坏的字符串对象的内部缓冲区的悬空指针。
您的代码对小字符串“有效”的原因可能是小字符串优化:短字符串(通常)保存在字符串对象本身中,而不是保存在动态分配的数组中,并且显然在您的情况下内存仍然可访问且未修改。
| 归档时间: |
|
| 查看次数: |
618 次 |
| 最近记录: |