调用string::c_str()
时,实际会执行什么操作?
字符串::c_str()
将分配内存,复制字符串对象的内部数据并在新分配的内存中追加一个以null结尾的字符?或者
在这个问题的答案的评论中有人说,C11要求std::string
为后面的'\0'
分配一个额外的char
。因此,第二种选择似乎是可能的。
另一个人说,std::string
操作——例如迭代、串联和元素突变——不需要零终止符。除非将字符串
传递给需要以零结尾的字符串的函数,否则可以忽略该字符串。
为什么实现者通常让. data()和.c_str()做同样的事情?
因为这样做效率更高。这是唯一的办法。data()返回不以null结尾的内容,这将是必须的。c_str()或。data()复制它们的内部缓冲区,或者只使用两个缓冲区。拥有一个以null结尾的缓冲区总是意味着在实现std::string时,始终可以只使用一个内部缓冲区。
所以我现在真的很困惑,当调用string::c_str()
时,实际会做什么?
更新:
如果c_str()
实现为简单地返回指针,则它已经被分配和管理。
A.由于c_str()
必须以null结尾,因此内部缓冲区需要始终以null结尾,即使对于空的std::string,例如:std::string demo_str
;,demo_str
的内存中应该有一个\0
。我说得对吗?
B.调用std::string::substr()
时会发生什么?自动将\0
附加到子字符串?
我们已经提供了很多很好的答案和评论。但是为了证明std::string
通常由以null结尾的字符串支持,我提供了一个简单但幼稚的实现。它不完整,不进行错误检查,当然也没有优化。但它已经足够完整,可以向您展示字符串类通常是如何使用以null结尾的缓冲区作为成员变量来实现的。
class string
{
public:
string()
{
assign("", 0);
}
string(const char* s)
{
assign(s, strlen(s));
}
string(const char* s, size_t len)
{
assign(s, len);
}
string(const string& s)
{
assign(s._ptr, s._len);
}
~string()
{
delete [] _ptr;
}
string& operator=(const string& s)
{
const char* oldptr = _ptr;
assign(s._ptr, s._len);
delete [] oldptr;
}
const char* data()
{
return _ptr;
}
const char* c_str()
{
return _ptr;
}
size_t length()
{
return _len;
}
// substr always returns a new string
std::string substr(size_t pos, size_t count)
{
std::string s(_ptr+pos, count);
return s;
}
private:
char* _ptr;
size_t _len;
void assign(const char* ptr, size_t len)
{
_len = len;
_ptr = new char[_len+1]; // +1 for null termination
memcpy(_ptr, ptr, len);
_ptr[_len] = '\0'; // always null terminate
}
};
这里有一个经验“证明”的复杂性。c_str()
是o(1):
#include <stdio.h>
#include <string>
using namespace std;
int main(int argc, char **argv)
{
std::string x(5000000, 'b'); // <--- single time allocation
// std::string x(5, 'b'); // <--- compare to a much shorter string
for (unsigned int i=0;i<1000000;i++)
{
const char *y = x.c_str(); // <--- copy entire content ?
}
}
-O0
编译以避免优化任何内容。调用c_str()
由于C11,std::字符串::c_str()
和std::字符串::data()
都需要返回指向字符串内部缓冲区的指针。由于c_str()
(但不是data()
)必须以null结尾,这实际上要求内部缓冲区始终以null结尾,尽管null终止符不按size()
/long()
计数,也不按std::字符串
迭代器等返回。
在C11之前,c_str()
的行为在技术上是特定于实现的,但是我见过的大多数实现都是这样工作的,因为这是实现它的最简单和最明智的方法。C11只是标准化了已经广泛使用的行为。
使现代化
从C 11开始,缓冲区总是以null结尾,即使对于空字符串也是如此。然而,这并不意味着当字符串为空时需要动态分配缓冲区。它可以指向SSO缓冲区,甚至可以指向单个静态
nul字符。无法保证字符串内容更改时,
c_str()
/data()
返回的指针仍指向同一内存地址。
std::string::substr()
返回一个新的std::string
,它有自己的以null结尾的缓冲区。从中复制的字符串不受影响。
本文向大家介绍请说明当PHP switch case执行case 0时会发生什么?,包括了请说明当PHP switch case执行case 0时会发生什么?的使用技巧和注意事项,需要的朋友参考一下 PHP是一种松散类型的语言。当与大小写0匹配时,字符串与最接近的整数匹配。 假设我们有以下开关表达式- 现在,我们将匹配情况0- 我们还将匹配非零情况- 示例 输出结果
我有一个ViewModel处理我的业务逻辑,我正在使用Koin将它注入到我的活动和每个片段中。然而,在我从片段A-片段B导航并导航回片段A之后,我的观察者再次被触发。为什么会发生这种情况?当我返回时,如何阻止这种onChanged被触发? 我尝试将'this'和'view LifecycleOwner'设置为LiveData的LifecycleOwner。 我还尝试将observable移动到on
根据对条件dplyr评估的讨论,我想根据传递的数据帧中是否存在参考列,有条件地在管道中执行一个步骤。 和生成的结果应该是相同的。 对于可用列,传递的对象与初始数据帧不对应。原始代码返回错误消息: :未找到对象 我尝试过其他语法(运气不佳): 我想扩展这个问题,以解释调用中右侧的评估。例如,下面的语法试图过滤第一个可用值。mtcars% 预期的是,调用的结果是错误消息: 中出错:结果的长度必须为32
我在写一个玩家轮流参加的游戏。在一个回合结束时,我将我的数据发送到服务器,并更新我的数据库,让我知道现在轮到另一个玩家了。问题是,如果有人在中途扼杀了应用程序怎么办?我是说去找任务经理然后杀了它。 编辑:我还应该提到这是在一个片段中,我正在检查这个,但不要认为这会有什么不同。
问题内容: 我阅读的所有资料都提到了几个案例,并以“其他一些案例”作了总结。在视图/活动中调用onSaveInstanceState方法时,所有情况是什么? 问题答案: 该文档称 在活动被杀死之前将调用此方法,以便将来在将来返回某个时间时可以恢复其状态。
问题内容: 当某些调用工作而另一些调用失败时,$ q.all()会发生什么? 我有以下代码: 当所有$ http调用都工作时,则allResponses数组将填充数据。 当我失败时,据我了解,第二个函数将被调用,并且错误变量将给出详细信息。 但是,有人可以帮我解释一下,如果某些响应有效而其他响应失败了怎么办? 问题答案: 我相信,由于Promise库是基于实现的,因此,一旦第一个Promise被拒