将std::string::c_str()进行深拷贝到char *

4

目前我有一个复杂的函数,我和我们的团队都不想重构它来使用std :: string,并且它需要修改char *。我如何正确地将string :: c_str()的深度副本制作成char *? 我想修改字符串内部存储的char *。

char *cstr = string.c_str();

因为c_str()是const,所以失败了。


4
这是C++11吗?复制std::string并使用&stringCopy[0]。 这句话的意思是询问是否为C++11语法,并建议通过复制std::string并使用&stringCopy[0]来实现某个目的。 - chris
1
strdupnew/strcpy,@chris的建议,……由您选择。 - syam
sprintf(cstr,"%s", somestring.c_str()) - bartimar
3个回答

8
你可以这样做:
const std::string::size_type size = string.size();
char *buffer = new char[size + 1];   //we need extra char for NUL
memcpy(buffer, string.c_str(), size + 1);

6
请使用正确的字符串大小类型,例如 std::string::size_typestd::size_t - syam
@syam 哦,你说得完全正确 :) - Michał Walenciak
1
不要忘记删除它。或者更好的方法是,让std::vector<char>为您完成此操作,并将数组作为v.data()&v[0]访问。甚至可以使用另一个string,如果您不介意边缘未定义的行为。 - Mike Seymour

4

不要修改现有的函数,而是创建一个充当包装器的重载。假设现有函数是ret_type f(char *),那么我会编写类似以下的重载:

ret_type f(std::string s) { 
    return f(&s[0]);
}

传递参数时,将字符串 s 按值而非按引用传递,以最小化获取字符串副本的努力。

理论上讲,在 C++03 之前并不能保证这种方式能够正常工作(即,一个字符串的缓冲区并不能保证连续)。实际上,委员会添加了这个保证是因为没有人知道 std::string 的实现会做其他的事情。

同样地,它理论上可能缺少 NUL 终止符。如果您担心这种可能性,可以使用 return f(const_cast<char *>(s.c_str()));,或在返回之前添加一个 s.push_back('\0');

ret_type f(std::string s) { 
    s.push_back('\0');
    return f(&s[0]);
}

我会在你的包装函数中执行s.push_back('\0'),以确保安全。而且你最后一段代码肯定是指的const_cast - James Kanze
@JamesKanze:糟糕——是的,当然。 - Jerry Coffin

1
明显的解决方案是:
std::vector<char> tmp( string.begin(), string.end() );
tmp.push_back( '\0' );
function( &tmp[0] );

我更喜欢Jerry Coffin的解决方案,但是。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接