为什么不允许通过检索到的数据指针修改字符串?

2024-01-12

在 C++11 中,a 的字符std::string必须连续存储,如 § 21.4.1/5 指出的:

basic_string 对象中的类字符对象应连续存储。也就是说,对于任何 basic_string 对象 s,恒等式 &*(s.begin() + n) == &*s.begin() + n 对于 n 的所有值都成立,使得 0

但是,第 21.4.7.1 节列出了检索指向底层存储的指针的两个函数(重点是我的):

const charT* c_str() const noexcept;
const charT* data() const noexcept;
1 返回:一个指针 p,对于 [0,size()] 中的每个 i,p + i == &operator[](i)。
2 复杂性:恒定时间。
3 要求:程序不得更改存储在字符数组中的任何值。

对于第 3 点,我能想到的一种可能性是,该指针可能会因对象的以下使用而变得无效(第 21.4.1/6 节):

  • 作为任何标准库函数的参数,将对非常量 basic_string 的引用作为 争论。
  • 调用非常量成员函数,operator[]、at、front、back、begin、rbegin、end 和 除外 撕裂。

即便如此,迭代器也可能会失效,但我们仍然可以修改它们,直到它们失效为止。我们仍然可以使用该指针,直到它也无法从缓冲区读取。

为什么我们不能直接写入这个缓冲区?是因为它会使类处于不一致的状态,例如,end()不会更新新结局吗?如果是这样,为什么允许直接写入类似的缓冲区std::vector?

其用例包括能够传递std::string到 C 接口来检索字符串而不是传入vector<char>相反,并使用迭代器初始化字符串:

std::string text;
text.resize(GetTextLength());
GetText(text.data());

为什么我们不能直接写入这个缓冲区?

我将陈述显而易见的一点:因为它是const。并抛弃一个const值然后修改该数据是......粗鲁的。

现在,这是为什么const?这可以追溯到写时复制被认为是一个好主意的时代,所以std::basic_string必须允许实现来支持它。获取指向字符串的不可变指针(例如,用于传递给 C-API)将非常有用without产生副本的开销。所以c_str需要返回一个const指针。

至于为什么是这样still const?嗯……这涉及到标准中的一个奇怪的事情:空终止符。

这是合法的代码:

std::string stupid;
const char *pointless = stupid.c_str();

pointless必须是以 NUL 结尾的字符串。具体来说,它必须是指向 NUL 字符的指针。那么NUL字符从何而来呢?有几种方法std::string实现以使其发挥作用:

  1. 使用小字符串优化,这是一种常见的技术。在这个方案中,每个std::string实现有一个内部缓冲区,可用于单个 NUL 字符。
  2. 返回一个指向静态存储器,包含 NUL 字符。因此,每std::string执行将返回same如果是空字符串则为指针。

不应强迫每个人都实施 SSO。因此,标准委员会需要一种方法来保留#2。其中一部分是给你一个const字符串来自c_str()。既然这段记忆很可能real const,不是假的“请不要修改此内存const,”给你一个指向它的可变指针是一个坏主意。

当然,你仍然可以通过这样做来获得这样的指针&str[0],但是标准很明确修改 NULL 终止符是一个坏主意 https://stackoverflow.com/questions/12740403/legal-to-overwrite-stdstrings-null-terminator.

现在,话虽如此,它是完全有效修改&str[0]指针,以及其中的字符数组。只要你保持在半开范围内 [0,str.size())。你只是不能通过返回的指针来做到这一点data or c_str。是的,尽管事实上标准requires str.c_str() == &str[0]是真实的。

这对你来说是标准的。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么不允许通过检索到的数据指针修改字符串? 的相关文章

  • 如何在多线程C++ 17程序中交换两个指针?

    我有两个指针 pA 和 pB 它们指向两个大的哈希映射对象 当pB指向的哈希图完全更新后 我想交换pB和pA 在C 17中 如何快速且线程安全地交换它们 原子 我是 c 17 的新手 2个指针的原子无等待交换可以通过以下方式实现 inclu
  • 为什么pow函数比简单运算慢?

    从我的一个朋友那里 我听说 pow 函数比简单地将底数乘以它的指数的等价函数要慢 例如 据他介绍 include
  • C++ 是否可以在 MacOS 上与 OpenMP 和 boost 兼容?

    我现在已经尝试了很多事情并得出了一些结论 也许 我监督了一些事情 但似乎我无法完成我想要的事情 问题是 是否有可能使用 OpenMP 和 boost 在 MacOS High Sierra 上编译 C 一些发现 如果我错了请纠正我 Open
  • 查看 NuGet 包依赖关系层次结构

    有没有一种方法 文本或图形 来查看 NuGet 包之间的依赖关系层次结构 如果您使用的是新的 csproj 您可以在此处获取所有依赖项 在项目构建后 项目目录 obj project assets json
  • unordered_map 中字符串的 C++ 哈希函数

    看起来 C 标准库中没有字符串的哈希函数 这是真的 在任何 c 编译器上使用字符串作为 unordered map 中的键的工作示例是什么 C STL提供模板专业化 http en cppreference com w cpp string
  • Python 属性和 Swig

    我正在尝试使用 swig 为一些 C 代码创建 python 绑定 我似乎遇到了一个问题 试图从我拥有的一些访问器函数创建 python 属性 方法如下 class Player public void entity Entity enti
  • 将 Long 转换为 DateTime 从 C# 日期到 Java 日期

    我一直尝试用Java读取二进制文件 而二进制文件是用C 编写的 其中一些数据包含日期时间数据 当 DateTime 数据写入文件 以二进制形式 时 它使用DateTime ToBinary on C 为了读取 DateTime 数据 它将首
  • C# 存档中的文件列表

    我正在创建一个 FileFinder 类 您可以在其中进行如下搜索 var fileFinder new FileFinder new string C MyFolder1 C MyFolder2 new string
  • 类型约束

    我有以下类层次结构 class Header IEnumerable
  • 识别 Visual Studio 中的重载运算符 (c++)

    有没有办法使用 Visual Studio 快速直观地识别 C 中的重载运算符 在我看来 C 中的一大问题是不知道您正在使用的运算符是否已重载 Visual Studio 或某些第三方工具中是否有某些功能可以自动突出显示重载运算符或对重载运
  • 如何在 Qt 应用程序中通过终端命令运行分离的应用程序?

    我想使用命令 cd opencv opencv 3 0 0 alpha samples cpp cpp example facedetect lena jpg 在 Qt 应用程序中按钮的 clicked 方法上运行 OpenCV 示例代码
  • 为什么从字典中获取时会得到 Action<> 的克隆?

    我有以下字典 private Dictionary
  • 在 NaN 情况下 to_string() 可以返回什么

    我使用 VS 2012 遇到了非常令人恼火的行为 有时我的浮点数是 NaN auto dbgHelp std to string myFloat dbgHelp最终包含5008角色 你不能发明这个东西 其中大部分为0 最终结果是 0 INF
  • 为什么我的单选按钮不起作用?

    我正在 Visual C 2005 中开发 MFC 对话框应用程序 我的单选按钮是 m Small m Medium 和 m Large 它们都没有在我的 m Summary 编辑框中显示应有的内容 可能出什么问题了 这是我的代码 Pizz
  • C++ int 前面加 0 会改变整个值

    我有一个非常奇怪的问题 如果我像这样声明一个 int int time 0110 然后将其显示到控制台返回的值为72 但是当我删除前面的 0 时int time 110 然后控制台显示110正如预期的那样 我想知道两件事 首先 为什么它在
  • 保护 APK 中的字符串

    我正在使用 Xamarin 的 Mono for Android 开发一个 Android 应用程序 我目前正在努力使用 Google Play API 添加应用内购买功能 为此 我需要从我的应用程序内向 Google 发送公共许可证密钥
  • 高效列出目录中的所有子目录

    请参阅迄今为止所采取的建议的编辑 我正在尝试使用 WinAPI 和 C 列出给定目录中的所有目录 文件夹 现在我的算法又慢又低效 使用 FindFirstFileEx 打开我正在搜索的文件夹 然后我查看目录中的每个文件 使用 FindNex
  • 使用 omp_set_num_threads() 将线程数设置为 2,但 omp_get_num_threads() 返回 1

    我有以下使用 OpenMP 的 C C 代码 int nProcessors omp get max threads if argv 4 NULL printf argv 4 s n argv 4 nProcessors atoi argv
  • 如何减少具有多个单元的 PdfPTable 的内存消耗

    我正在使用 ITextSharp 创建一个 PDF 它由单个 PdfTable 组成 不幸的是 对于特定的数据集 由于创建了大量 PdfPCell 我遇到了内存不足异常 我已经分析了内存使用情况 我有近百万个单元格的 1 2 在这种情况下有
  • 如何使用 C++11 using 语法键入定义函数指针?

    我想写这个 typedef void FunctionPtr using using 我该怎么做呢 它具有类似的语法 只不过您从指针中删除了标识符 using FunctionPtr void 这是一个Example http ideone

随机推荐