将常量字符* 返回到字符*,然后更改数据



我对以下代码感到困惑:

string _str = "SDFDFSD";
char* pStr = (char*)_str.data();
for (int i = 0; i < iSize; i++)
    pStr[i] = ::tolower(pStr[i]);

在这里_str.data()返回const char*.但是我们正在将其分配给一个char*.我的问题是,

_str.data()返回指向常量数据的指针。如何将其存储在指向数据的指针中?数据是恒定的吧?如果我们将其分配给 char 指针,那么我们可以像在 for 语句中所做的那样更改它,这对于常量数据来说是不可能的。

不要那样做。在这种情况下可能没问题,但正如data()的文档所说:

返回的指针可能会因进一步调用其他指针而失效 修改对象的成员函数。

程序不得更改此序列中的任何字符。

因此,如果您保留该指针,您可能会非常意外地写入无效内存。或者,事实上,破坏了 std::string 的实现。我几乎可以说这个函数不应该公开。

std::string 为此提供了一个非常量operator[]

string _str = "SDFDFSD";
for (int i = 0; i < iSize; i++)
    _str[i] = ::tolower(_str[i]);

您正在执行的操作在标准库级别无效(您违反了std::string contract),但在C++核心语言级别有效。

不应写入从 data 返回的char *,因为例如,理论上它可能在具有相同值的不同字符串之间共享 (*)。

如果要修改字符串,只需使用std::string::operator[],它将通知对象意图,并负责为特定实例创建私有缓冲区,以防字符串最初是共享的。

从技术上讲,您可以从指针或引用中丢弃常量,但它是否是有效的操作取决于特定情况的语义。允许该操作的原因是C++的主要哲学是程序员不会犯错误并且知道他们在做什么。例如,从C++语言的角度来看,在x是一个类实例的情况下做memcpy(&x, "hello", 5)在技术上是合法的,但结果很可能是"未定义的行为"。

如果你认为你的代码"有效",

那是因为你对"有效"的真正含义有错误的理解(提示:"有效"并不意味着有人曾经观察到代码在做看似合理的事情,但这在所有情况下都有效)。如果你运行该程序,一个有效的C++实现可以自由地做任何它想做的事情:你观察到一些你认为很好的东西并不意味着什么,可能是你看起来不够近,或者你只是幸运(不幸的是,实际上)没有立即发生崩溃。

(*) 在现代,std::string 的 COW(写入时复制)实现的受欢迎程度很低,因为它们会带来很多问题(例如多线程),而且内存现在便宜得多。仍然std::string合约说不允许更改 data() 的返回值所指向的内存;如果你做任何事情都可能发生。

永远不必直接更改从std::string::data()std::string::c_str()返回的数据。

要创建std::string的副本:

std::string str1 = "test";
std::string str2 = str1; // copy.

更改字符串中的字符:

std::string str1 = "test"
str1[0] = 'T';

"正确"的方法是改用std::transform

std::transform(_str.begin(), _str.end(), _str.begin(), ::tolower);

你的问题的简单答案是,在C++中你可以抛弃变量的"常量"。

你可能不应该。

请参阅此内容以了解C++中的常量正确性

字符串总是在堆上分配内存,所以这实际上不是 const 数据,它只是被标记为 (在方法 data() 签名中)以防止修改。

但是在C++中没有什么是不可能的,所以通过简单的强制转换,虽然不安全,你现在可以将相同的内存空间视为可修改的。

C/C++ 程序中的所有常量(如下"SDFDFSD")将存储在单独的部分中.rodata .在执行期间将二进制文件加载到内存中时,此部分将映射为只读。

int main()
{
  char* ptr = "SDFDFSD";
  ptr[0]='x'; //segmentation fault!!
  return 0;
}

因此,任何修改该位置数据的尝试都将导致运行时错误,即分段错误


谈到上面的问题,当创建一个字符串并为其分配一个字符串时,内存中现在存在一个新的副本(内存用于保存字符串对象的属性_str)。这是在堆上,而不是映射到只读部分。成员函数_str.data()指向内存中映射为读/写的位置。

返回类型的const限定符可确保此函数不会意外传递给需要非常量char*指针的字符串操作函数。

在当前的迭代中,保存字符串对象数据的内存位置本身没有限制;即它被映射为读/写权限。因此,使用另一个非常量指针修改位置是有效的,即 分配左侧的pStr[i]不会导致运行时错误,因为内存位置本身没有固有的限制。

同样,这不能保证有效,只是您观察到的特定于实现的行为(即它恰好对您有用),并且不能总是依赖于此。

相关内容

  • 没有找到相关文章

最新更新