6

我有一个简单的程序:

#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[], --alloc-fns, etc.

-> 16.67% (4B) 0x400A0B: read0() (main.cpp:10)

-> 16.67% (4B) 0x400BC8: 主要 (main.cpp:40)

对于 read1 和 read2:

72.50% (29B) (堆分配函数) malloc/new/new[], --alloc-fns, etc.

->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.cpp:40)

是什么导致了这种差异?

4

2 回答 2

8

如果我错了,请有人纠正我,但我想我知道这是为什么。

read0中,您可以:

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

你根本不初始化cstr,所以它可能是未定义的。字符串构造函数接受一个以null 结尾的c-string 并将其复制到 null 终止符。我认为它在第一个元素处找到它,所以它只是复制指向这样一个字符串的指针,它大概占用 4 个字节。

我觉得你的read1很相似。它最终在字符串本身之后的某个点找到了一个空终止符,因为它不是空终止的,最终是 29 个字节。

read2老实说,我不知道为什么会做同样的事情。上面的原因可能是我错了read1,29 个字节(减去 c 字符串中的 4 个字符/字节)是您的体系结构和编译器的 STL 实现中字符串的最小操作成本。

在任何情况下,为了缩小各种可能性,我建议您以空值终止字符串,read0然后read1通过分配一个额外元素并将最后一个元素设置为'\0'或使用采用额外第二个参数的替代字符串构造函数来再次尝试您的实验这表示要复制多少个字符:

string(non_null_terminated_string, this_many_characters_to_copy)
于 2013-03-15T01:42:13.470 回答
1

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

此外,您的 read1 有问题:如果您希望 cstr 包含“----”,那么您需要 cstr[5],而不是 cstr[4]。您的数组需要空间用于以字符串结尾的零。然后你可能应该使用 strcpy(cstr, "----") 而不是 memset(cstr, '-', 4) 否则 cstr 将没有(需要的)零终止符。

于 2013-03-15T01:54:32.600 回答