我最近开始使用C ++,在使用malloc时遇到了问题。 下面的代码不会打印出“成功”(程序崩溃,退出代码0xC0000005),但是如果我使用calloc,则一切正常。
calloc(4, sizeof(std::string));
下面的代码有效。
var width = +svg.attr('width');
var height = +svg.attr('height');
var x = d3.scaleBand().range([0, width]).padding(.1);
var y = d3.scaleLinear().range([0, height]).domain([0, 100]);
如果我的分配是正常数量的12倍,则Malloc也可以工作。
有人可以解释这种行为吗?这与std :: string有关吗?
答案 0 :(得分:7)
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);
答案 1 :(得分:5)
有人可以解释这种行为吗?
在两种情况下,行为均未定义。 calloc
案例似乎奏效的原因仅仅是运气不好。
要在分配的内存空间中使用对象,必须首先 construct 。您从未构造任何字符串对象。
构造动态分配的对象数组的最简单方法是使用向量:
std::vector<std::string> vec(4);