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++ 程序员介绍 malloc
或 calloc
创建对象。或者您正在阅读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)