malloc和calloc与std :: string之间的区别

时间:2018-08-12 12:05:41

标签: c++ malloc stdstring calloc

我最近开始使用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有关吗?

2 个答案:

答案 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);