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

Tin*_*lam 1 c++ malloc stdstring calloc

我最近进入了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;
}
Run Code Online (Sandbox Code Playgroud)

以下代码有效.

calloc(4, sizeof(std::string));
Run Code Online (Sandbox Code Playgroud)

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

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

Mic*_*ler 7

std::string* pointer = (std::string*) malloc(4 * sizeof(std::string)); 
Run Code Online (Sandbox Code Playgroud)

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

编辑:至于它为何与calloc一起工作:最有可能的是,默认构造函数 std::string将所有字段设置为零.可能calloc恰好和你系统上的std :: string默认构造一样.相反,小的malloc()对象可能分配了初始垃圾,因此对象不处于有效状态

足够大malloc()的效果类似于calloc().当malloc()无法重用先前分配的块(具有潜在垃圾)时,它从操作系统请求新块.通常操作系统会清除它对应用程序的任何阻止(以避免信息泄漏),使大malloc()的行为类似于calloc().

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

最简单的解决方案是让C++处理分配和构造,然后再进行破坏和释放.这自动完成了

std::vector<std::string> str_vec(4);
Run Code Online (Sandbox Code Playgroud)

如果你坚持分配和释放自己的内存(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;
Run Code Online (Sandbox Code Playgroud)

如果由于某些奇怪的原因你仍然想使用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);
Run Code Online (Sandbox Code Playgroud)


eer*_*ika 5

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

在这两种情况下,行为都是不确定的.calloc似乎工作的案件仅仅是因为运气不好.

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

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

std::vector<std::string> vec(4);
Run Code Online (Sandbox Code Playgroud)