修改c ++字符串对象的底层char数组

时间:2011-04-20 11:00:12

标签: c++ arrays string

我的代码是这样的:

string s = "abc";
char* pc = const_cast<char*>( s.c_str() );
pc[ 1 ] = 'x';
cout << s << endl;

当我使用GCC编译上面的代码片段时,我得到了结果“axc”。我的问题是,以这种方式修改C ++字符串的基础char数组是否安全且可移植?或者可能有其他方法直接操作字符串数据?

仅供参考,我的目的是编写一些可由C和C ++调用的纯C函数,因此,它们只能接受char*作为参数。从char*到字符串,我知道涉及复制,惩罚是不利的。所以,任何人都可以提出一些建议来处理这种情况。

7 个答案:

答案 0 :(得分:5)

(a)这不一定是基础字符串。 std::string::c_str()应该是底层字符串的副本(尽管C ++标准中的一个错误意味着,实际上,它通常不是......我相信这在C ++ 0x中得到修复)。

(b)const_cast离开constness只会破坏变量类型:实际对象仍然是const,你修改它是未定义的行为 - 非常糟糕。

简单地说,这样做。


你可以使用&myString[0]吗?它有一个非const版本;然后,它被声明与没有非const版本的data()[0]相同。有一个像样的库参考的人可以清除它。

答案 1 :(得分:5)

对于第一部分,c_str()返回const char*,这意味着它所说的内容。在这种情况下,所有const_cast都会实现未定义的行为编译。

对于第二部分,在C ++中,0x std::string保证具有连续存储,就像C ++ 03中的std::vector一样。因此,只要字符串不为空,您就可以使用&s[0]char*传递给函数。在实践中,目前处于活动开发状态的所有string实现已经具有连续存储:在标准委员会会议上进行了一次民意调查,没有人提供反例。因此,如果您愿意,可以立即使用此功能。

然而std::string使用与C风格字符串完全不同的字符串格式,即数据+长度而不是nul-terminated。如果从C函数修改字符串数据,则无法更改字符串的长度,并且无法确定在没有c_str()的情况下末尾有一个空字节。并且std::string可以包含作为数据一部分的嵌入式nuls,所以即使你确实找到了一个nul,在不知道长度的情况下你仍然不知道你已经找到了字符串的结尾。对于能够在不同类型的数据上正确运行的函数,您可以做的非常有限。

答案 2 :(得分:3)

正如其他人所说,它不便携。但是还有更多的危险。一些std :: string实现(我知道GCC会这样做)使用COW(写入时复制)。

#include <iostream>
#include <string>

int main()
{

    std::string x("abc");
    std::string y;
    y = x; // x and y share the same buffer

    std::cout << (void*)&x[0] << '\n';
    std::cout << (void*)&y[0] << '\n';

    x[0] = 'A'; // COW triggered

    // x and y no longer share the same buffer
    std::cout << (void*)&x[0] << '\n';
    std::cout << (void*)&y[0] << '\n';

    return 0;
}

答案 3 :(得分:2)

显而易见的答案是否定的,这是未定义的行为。在另一 亲手,如果你这样做:

char* pc = &s[0];

您可以在今天的实践中访问基础数据 在C ++ 11中得到保证。

答案 4 :(得分:1)

这依赖于未定义的行为,因此不可移植。

答案 5 :(得分:1)

这取决于您的操作系统。在GNU libc库中,std::string使用copy-on-write (CoW) pattern实现。因此,如果多个std::string对象最初包含相同的内容,则它们将在内部全部指向相同的数据。因此,如果您在问题中显示的方法中修改其中的任何一个,则所有(看似)不相关的std::string对象的内容都将发生变化。

在Windows上,我认为实现不使用CoW,我不确定那里会发生什么。

无论如何,它是未定义的行为,所以我要保持清醒。有可能,即使你让它工作,你最终也会陷入非常难以追查的错误。

答案 6 :(得分:0)

你不应该搞乱底层字符串。在一天结束时,字符串是一个对象,你会以这种方式混淆任何其他对象吗?

您是否剖析了代码以查看是否存在惩罚。