Red*_*dex 2 c++ string heap-memory
我在堆上为字符串数组分配内存时遇到问题。分配新的工作,但每次 malloc 都会出现段错误。我首先想使用 malloc 的原因是我不想不必要地调用构造函数。
这很好用
std::string* strings = new std::string[6];
Run Code Online (Sandbox Code Playgroud)
这不
std::string* strings = (std::string *)malloc(sizeof(std::string[6]));
Run Code Online (Sandbox Code Playgroud)
我注意到的一件事是,第一个变体(使用 new)分配 248 字节内存,而第二个变体仅分配 240 字节。无论我收集到的数组大小如何,这个 8 字节差异都是恒定的,而且我找不到差异的根源是什么。
这是出现段错误的整个代码。
#include <iostream>
void* operator new(size_t size)
{
std::cout << size << std::endl;
return malloc(size);
}
void* operator new [](size_t size)
{
std::cout << size << std::endl;
return malloc(size);
}
int main() {
std::string* strings = new std::string[6];
strings = (std::string *)malloc(sizeof(std::string[6]));
strings[0] = std::string("test");
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我注意到的另一件事是,如果我在 malloc 之后使用 memset 将我用 malloc 分配的所有字节设置为 0,上面的代码似乎可以工作。我不明白 8 字节差异来自哪里,如果这有效的话,而且为什么这个变体有效。为什么仅仅因为我将所有字节设置为 0 它就会起作用?
malloc()
仅分配原始内存,但不会在该内存内构造任何对象。
new
并且new[]
都分配内存和构造对象。
如果你真的想用它malloc()
来创建一个 C++ 对象数组(你真的不应该这样做!),那么你必须使用 自己调用对象构造函数placement-new
,并在释放内存之前自己调用对象析构函数,例如:
std::string* strings = static_cast<std::string*>(
malloc(sizeof(std::string) * 6)
);
for(int i = 0; i < 6; ++i) {
new (&strings[i]) std::string;
}
...
for(int i = 0; i < 6; ++i) {
strings[i].~std::string();
}
free(strings);
Run Code Online (Sandbox Code Playgroud)
在 C++11 和 C++14 中,您应该使用std::aligned_storage
来帮助计算数组内存的必要大小,例如:
using string_storage = std::aligned_storage<sizeof(std::string), alignof(std::string)>::type;
void *buffer = malloc(sizeof(string_storage) * 6);
std::string* strings = reinterpret_cast<std::string*>(buffer);
for(int i = 0; i < 6; ++i) {
new (&strings[i]) std::string;
}
...
for(int i = 0; i < 6; ++i) {
strings[i].~std::string();
}
free(buffer);
Run Code Online (Sandbox Code Playgroud)
在 C++17 及更高版本中,您应该使用std::aligned_alloc()
而不是malloc()
直接使用,例如:
std::string* strings = static_cast<std::string*>(
std::aligned_alloc(alignof(std::string), sizeof(std::string) * 6)
);
for(int i = 0; i < 6; ++i) {
new (&strings[i]) std::string;
}
...
for(int i = 0; i < 6; ++i) {
strings[i].~std::string();
}
std::free(strings);
Run Code Online (Sandbox Code Playgroud)
分配vianew
意味着构造函数被运行。new
只要有可能,请始终将anddelete
与 C++ 类(并且std::string
是 C++ 类)一起使用。
当您执行malloc()
/时free()
,仅完成内存分配,不运行构造函数(析构函数)。这意味着,该对象尚未初始化。从技术上讲,您可能仍然可以使用放置new
(即new(pointer) Type
)来初始化它,但使用 classic 更好且更一致new
。
如果您想分配多个对象,这就是容器的用途。请使用它们。多名顶级工程师致力于std::vector<>
、std::array<>
、std::set<>
、std::map<>
工作并达到最佳状态 -在性能、稳定性或其他指标上很难击败他们,即使你做到了,同一家公司的下一个编码员也需要了解你的特定数据结构。因此,建议不要在可以使用容器的地方使用自定义和本地实现的分配,除非有非常充分的理由(或者当然是教学目的)。
归档时间: |
|
查看次数: |
326 次 |
最近记录: |