malloc 和 calloc 与 std::string 的区别

Posted

技术标签:

【中文标题】malloc 和 calloc 与 std::string 的区别【英文标题】:Difference between malloc and calloc with std::string 【发布时间】:2018-08-12 12:05:41 【问题描述】:

我最近接触了 C++,但在使用 malloc 时遇到了问题。 下面的代码不会打印出“成功”(程序崩溃,退出代码为 0xC0000005),而如果我使用 calloc 代替,一切正常。

int main()
    std::string* pointer = (std::string*) malloc(4 * sizeof(std::string));

    for(int i = 0; i < 4; i++)
        pointer[i] = "test";
    

    std::cout << "Success" << std::endl;

    return 0;

下面的代码有效。

calloc(4, sizeof(std::string));

如果我分配正常数量的 12 倍,Malloc 也可以工作。

有人可以解释这种行为吗?这和 std::string 有关系吗?

【问题讨论】:

考虑阅读good book。 不要在 C++ 中使用 malloc/calloc/realloc/free。使用正确调用构造函数/析构函数的new/new[]/delete/delete。或者更好的是,使用容器和/或智能指针。避免手动内存管理。 问题是你没有构建需要的字符串.....如果你决定使用malloc你需要放置new你之前得到的内存你把它当作一个字符串...... 我认为它初始化了字符串本身它不构造字符串。你使用它的方式是UB。 @TinSlam 我最近接触了 C++ -- 自从你刚接触 C++ 以来,你都在读什么书?我所知道的没有一本书向 C++ 程序员介绍 malloccalloc 创建对象。或者您正在阅读C 书籍并将其应用于C++?如果是这样,你会犯更多类似于你现在犯的错误。 【参考方案1】:
std::string* pointer = (std::string*) malloc(4 * sizeof(std::string)); 

这仅分配足以容纳 4 个字符串对象的内存。它不构造它们,构造之前的任何使用都是未定义的。

编辑:至于为什么它与 calloc 一起使用:很可能,std::string 的默认构造函数将所有字段设置为零。可能 calloc 恰好与系统上的 std::string 默认构造相同。相比之下,小的 malloc() 对象可能分配有初始垃圾,因此对象不处于有效状态

使用足够大的malloc(),效果类似于calloc()。当malloc() 不能重用以前分配的块(可能是垃圾)时,它会从操作系统请求新块。通常操作系统会清除它交给应用程序的任何块(以避免信息泄漏),使大 malloc() 的行为类似于 calloc()。

这不适用于所有系统和编译器这取决于编译器如何实现std::string 并取决于未定义的行为如何混淆编译器。这意味着,如果它现在可以在您的编译器上运行,它可能无法在不同的系统上运行,或者在更新的编译器上运行。更糟糕的是,在您在程序中编辑看似不相关的代码后,它可能会停止使用您的编译器在您的系统上运行永远不要依赖未定义的行为

最简单的解决方案是让 C++ 处理分配和构造,然后再处理销毁和释放。这由

自动完成
std::vector<std::string> str_vec(4);

如果你坚持分配和释放你自己的内存(99.9% 的情况下这是个坏主意),你应该使用new 而不是malloc。与malloc() 不同,使用new 实际上是构造对象。

// better use std::unique_ptr<std::string[]>
// since at least it automatically
// destroys and frees the objects.
std::string* pointer = new std::string[4];

... use the pointer ...

// better to rely on std::unique_ptr to auto delete the thing.
delete [] pointer;

如果出于某种奇怪的原因您仍想使用 malloc(99.99% 的情况下这是个坏主意),您必须自己构造和销毁对象:

constexpr int size = 4;
std::string* pointer = (std::string*) malloc(size * sizeof(std::string)); 
for (int i=0; i != size ;++i)
    // placement new constructs the strings
    new (pointer+i) std::string;

... use the pointer ....

for (int i=0; i != size ;++i)
    // destruct the strings
    pointer[i].~string();
free(pointer);

【讨论】:

你不应该转换 new 的结果。指针的类型已经正确。 @user2079303 谢谢。手机上复制粘贴的奇迹再次来袭。【参考方案2】:

有人可以解释这种行为吗?

这两种情况下的行为都是未定义的。 calloc 的案例似乎有效只是因为运气不好。

为了在分配的内存空间中使用一个对象,你必须首先构造这个对象。您从未构造过任何字符串对象。

构造动态分配的对象数组的最简单方法是使用向量:

std::vector<std::string> vec(4);

【讨论】:

以上是关于malloc 和 calloc 与 std::string 的区别的主要内容,如果未能解决你的问题,请参考以下文章

posix_memalign、malloc 和 calloc 与 lli 解释器有问题

堆的分配和释放(malloc,free,calloc,realloc)

malloc()与calloc区别

内存动态分配之realloc(),malloc(),calloc()与new运算符

malloc,realloc,与calloc

C ++中的“new”和“malloc”和“calloc”有啥区别? [复制]