【问题标题】:why is string s = (char*)tag.c_str(); is wrong when tag is a string为什么字符串 s = (char*)tag.c_str();当标签是字符串时是错误的
【发布时间】:2021-03-15 08:49:45
【问题描述】:

为什么下面的代码是错误的?

string tag = "hello"; string s = (char*)tag.c_str();

这是什么意思:storing addresses to internal storage of temporary string objects is wrong. 有人可以帮忙吗?在上述转换过程中究竟发生了什么?

【问题讨论】:

  • 我认为错误信息不正确。什么在生产它?当然,您不需要 (char*) 演员表。在这两种情况下,所发生的只是分配了新的存储空间并将字符复制到新的存储空间,因此没有存储地址。
  • (char*)tag.c_str() 是什么意思? c_str() 已经返回一个 const char* 并且 std::string 有一个构造函数,它采用 const char*。但是否则你的代码是好的,你没有发布的代码中一定有不同的错误。
  • 为什么要将c_str() 指针转换为非常量char*c_str() 返回一个const char*std::string 有一个构造函数和赋值运算符,它们接受const char* 作为输入。 string s = tag.c_str(); 可以正常工作(但您应该改用 string s = tag;)。
  • 该消息是否准确地引用了该代码?在我看来,您似乎有一个过于敏感的静态分析工具。

标签: c++ string pointers char


【解决方案1】:

对于所示示例,引用的消息是错误的,因为tag 不是“临时字符串对象”,而是一个生命周期比指针更长的变量。这也是错误的,因为该指针仅在调用c_str 的完整表达式中使用,因此该指针没有被“存储”以备后用。

char* 的强制转换是不必要的,应该删除。此外,无需调用c_str。复制字符串的一种更简单的方法是:

std::string s = tag; 

这是一个错误程序,其消息是正确的:

const char* wrong = "wrong"s.c_str(); // don't do this
std::cout << wrong; // kaboom; behaviour of program is undefined

这里存储的是临时字符串对象的内部存储地址,这是错误的,因为临时字符串对象立即被销毁,因此指针无效,因此无用。

【讨论】:

    【解决方案2】:

    string tag = "hello";

    初始化tag 对象,其值为"hello"。正是 hos tag 这样做不是您关心的问题。它做到了,这就是您需要知道的全部内容(目前)。

    string s = (char*)tag.c_str();

    首先您要求tag 对象允许您访问其存储字符串数据的内部缓冲区(参见c_str() 描述)。然后更改原始返回类型 (const char*),然后使用它来初始化新的 std::string 对象。

    我不知道您对s 有什么意图,但以下选项之一会是更好的选择:

    std::string s = tag; // s is now a copy of tag.
    std::string &s = tag; // s is now a reference to tag (what you do t s will be reflected on tag).
    std::string s(std::move(tag)); // contents of tag moved to s
    

    如果由于某种原因您需要访问隐藏在 std::string 中的内存(这就是 c_str() 方法所做的),您绝对不应该丢弃 const。您可能认为它有效,但最好说现在有效

    不仅将地址存储到临时字符串对象的内部存储器是错误的,而且大多数情况下将地址存储到字符串的内部存储器也是错误的——它是一个临时对象的事实只会让情况变得更糟。这里有两个原因:

    1. 由于对象是临时的,这意味着该地址在对象被销毁的那一刻肯定是无效的。 invalid 我的意思是它将不再指向字符串的开头。它仍然会指向某个地方,但谁知道会是这样。
    2. 即使对象不是临时的,存储该地址也是危险的。假设有人为该字符串分配了一个新值,很长。 std::string 的实现方式可能导致分配或重新分配。这意味着对象现在使用不同的位置来存储其数据。旧的地方被释放,因此可供其他人重用。你还拿着现在指向什么的旧指针?谁知道呢!

    【讨论】:

    • string s = (char*)tag.c_str();不会将tag的内容的地址存储在s中。它复制c_str() 给出的以null 结尾的字符串的内容。所以string s = tag.c_str(); 是(如果tag 在字符串中间不包含\0)将具有与std::string s = tag; 相同的结果
    猜你喜欢
    • 2021-03-16
    • 2022-12-08
    • 2014-11-20
    • 1970-01-01
    • 1970-01-01
    • 2020-09-25
    • 2014-01-16
    • 1970-01-01
    相关资源
    最近更新 更多