首页 文章

引擎盖下的c字符串构造函数

提问于
浏览
3

我有一个简单的程序:

#include <iostream>
#include <string>
#include <string.h>

using namespace std;

string read0() {
    int length = 4;

    char *cstr = new char[length];

    string str(cstr);

    delete[] cstr;

    return str;
}

string read1() {
    int length = 4;

    char cstr[length];

    memset(cstr, '-', 4);

    string str(cstr);

   return str;
}

string read2() {
    const char* cstr = "abcd";

    string str(cstr);

    return str;
}

在上面的所有3个函数中,为了构造一个字符串,它们是 call basic_string( const CharT* s, const Allocator& alloc = Allocator() . 当我使用valgrind / massif检查堆使用情况时,函数read0仅使用4个字节(来自 new ),但read1和read2都使用29个字节 .

这是地块的一些细节输出:

对于read0:

16.67%(4B)(堆分配函数)malloc / new / new [], - all-fns等 - > 16.67%(4B)0x400A0B:read0()(main.cpp:10) - > 16.67% (4B)0x400BC8:main(main.cpp:40)

对于read1和read2:

72.50%(29B)(堆分配函数)malloc / new / new [], - all-fns等 - > 72.50%(29B)0x4EE93B7:std :: string :: _ Rep :: _ S_create(unsigned long, unsigned long,std :: allocator const&)(在/ usr / lib / x86_64-linux-gnu / libstdc .so.6.0.17中) - > 72.50%(29B)0x4EEAD93:char * std :: string :: _ S_construct(char const *,char const *,std :: allocator const&,std :: forward_iterator_tag)(在/ usr / lib / x86_64-linux-gnu / libstdc .so.6.0.17中) - > 72.50%(29B)0x4EEAE71:std: :basic_string,std :: allocator> :: basic_string(char const *,std :: allocator const&)(在/ usr / lib / x86_64-linux-gnu / libstdc .so.6.0.17中) - > 72.50%(29B) 0x400B81:read2()(main.cpp:34) - > 72.50%(29B)0x400BC8:main(main.cpp:40)

是什么导致这种差异?

2 回答

  • 7

    如果我错了,请有人纠正我,但我想我知道为什么会这样 .

    read0 中,您可以:

    char *cstr = new char[length];
    string str(cstr);
    

    您根本没有初始化 cstr ,因此可能未定义 . 字符串构造函数采用 null-terminated c-string并将其复制until the null terminator . 我认为它在第一个元素处找到它,所以它只复制指向这样一个字符串的指针,这可能占用4个字节 .

    我认为你的 read1 是相似的 . 它最终在字符串本身的某个点找到一个空终止符,因为它不是以空值终止的,最终是29个字节 .

    我不知道为什么 read2 在做同样的事情,说实话 . 可能我上面的 read1 的原因是错的,29个字节(减去c字符串中的4个字符/字节)是架构和编译器实现STL时字符串的最小运行成本 .

    In any case ,为了缩小各种可能性,我建议你在 read0read1 中空终止字符串,然后通过分配一个额外的元素并将最后一个元素设置为 '\0' 或者使用另外一个额外的字符串构造函数再次尝试实验参数,表示要复制的字符数:

    string(non_null_terminated_string, this_many_characters_to_copy)
    
  • 1

    在read0中,您正在从cstr初始化str,它是空的(零长度) . 在read1和read2中,您正在从非空字符串初始化str . 在后一种情况下(29字节)实际分配的堆大于严格必要的堆,以使堆管理更快更简单 - 例如,以32字节(或其他一些舍入数字)的块分配堆并不罕见 .

    此外,你的read1被窃听:如果你想让cstr包含“----”,那么你需要cstr [5],而不是cstr [4] . 您的数组需要空间用于字符串终止零 . 然后你应该使用strcpy(cstr,“----”)而不是memset(cstr,' - ',4),否则cstr将没有(所需的)零终止符 .

相关问题