7

这似乎是一个愚蠢的问题,但我真的需要澄清这一点:

这会给我的程序带来任何危险吗?

const_cast甚至需要吗?

如果我更改输入指针值,它将安全地工作std::string还是会产生未定义的行为?

到目前为止,唯一担心的是,每当我修改输入指针并使其无法使用时,这可能会影响字符串“some_text”。

std::string some_text = "Text with some input";

char * input = const_cast<char*>(some_text.c_str());

感谢您给我一些提示,我想避免在我自己的脚上射击

4

9 回答 9

14

作为邪恶行为的一个例子:与 gcc 的 Copy On Write 实现的交互。

#include <string>
#include <iostream>

int main() {
    std::string const original = "Hello, World!";
    std::string copy = original;

    char* c = const_cast<char*>(copy.c_str());
    c[0] = 'J';

    std::cout << original << "\n";
}

ideone行动。

果冻,世界!

问题 ?顾名思义,gcc 的实现在底层std::string使用了一个引用计数的共享缓冲区。当一个字符串被修改时,实现会巧妙地检查当前缓冲区是否被共享,如果是,则在修改之前复制它,确保共享该缓冲区的其他字符串不受新写入的影响(因此名称,写时复制)。

现在,使用您的邪恶程序,您通过 const 方法访问共享缓冲区(承诺不修改任何内容),但您确实修改了它!

请注意,对于不使用写时复制的 MSVC 实现,行为会有所不同("Hello, World!"将正确打印)。

这正是Undefined Behavior的本质。

于 2012-04-24T08:02:03.567 回答
5

使用Undefined Behaviorconst通过抛弃它的常量来修改一个固有的对象。 const_cast

string::c_str()返回 aconst char *,即:指向常量 c 样式字符串的指针。从技术上讲,修改它会导致未定义的行为。

请注意,const_cast当您有一个const指向非常量数据的指针并且您希望修改非常量数据时,使用 。

于 2012-04-24T07:48:16.710 回答
4

简单的强制转换不会带来未定义的行为。然而,修改指向的数据将会。(另见 ISO 14882:98 5.2.7-7)。

如果你想要一个指向可修改数据的指针,你可以有一个

std::vector<char> wtf(str.begin(), str.end());
char* lol= &wtf[0];
于 2012-04-24T07:54:10.950 回答
2

内部std::string管理它自己的内存,这就是为什么它直接返回一个指向该内存的指针,就像它对c_str()函数所做的那样。它确保它是恒定的,以便您的编译器在您尝试修改它时会警告您。

以这种方式使用 const_cast 从字面上消除了这种安全性,并且如果您绝对确定不会修改内存,那么这只是一种可以接受的做法。

如果你不能保证这一点,那么你必须复制字符串并使用副本。; 在任何情况下这样做肯定会更安全(您可以使用strcpy)。

于 2012-04-24T07:52:03.680 回答
2

请参阅C++ 参考网站:

const char* c_str ( ) const;

“生成一个以空字符结尾的字符序列(c-string),其内容与字符串对象相同,并将其作为指向字符数组的指针返回。

自动附加终止空字符。

返回的数组指向一个内部位置,该位置具有该字符序列所需的存储空间以及它的终止空字符,但是该数组中的值不应在程序中修改,并且只能保证在下一次调用之前保持不变字符串对象的非常量成员函数。”

于 2012-04-24T07:52:05.830 回答
1

是的,它会带来危险,因为

  1. input指向c_str现在发生的任何事情,但如果some_text发生变化或消失,您将留下一个指向垃圾的指针。的值c_str保证只有在字符串不改变时才有效。甚至,正式地,只有在你不调用c_str()其他字符串的情况下。
  2. 为什么你需要抛弃 const?你不打算写信给*input,是吗?这是一个禁忌!
于 2012-04-24T07:51:35.197 回答
1

这是一件非常糟糕的事情。看看 std::string::c_str()了什么并同意我的看法。

其次,考虑为什么要对 std::string 的内部进行非常量访问。显然您想修改内容,否则您将使用 const char 指针。您还担心您不想更改原始字符串。为什么不写

std::string input( some_text );

然后你有一个 std::string 可以在不影响原始文件的情况下搞乱,并且你有 std::string 功能,而不必使用原始 C++ 指针......

于 2012-04-24T07:55:55.190 回答
1

另一个问题是它使代码极难维护。举个例子:几年前,我不得不重构一些包含长函数的代码。作者编写了函数签名来接受 const 参数,但随后const_cast在函数中使用它们以删除 const 性。这破坏了函数给出的隐含保证,并且很难知道参数是否在代码主体的其余部分中发生了变化。

简而言之,如果您可以控制字符串并且您认为需要更改它,请首先将其设为非 const。如果你不这样做,那么你将不得不复制并使用它。

于 2012-04-24T08:02:16.247 回答
1

它是UB。例如,您可以这样做:

size_t const size = (sizeof(int) == 4 ? 1024 : 2048);
int arr[size];

没有任何强制转换,编译器不会报告错误。但是这个代码是非法的。士气是您每次都需要考虑采取行动。

于 2012-04-24T08:39:10.083 回答