我目前正在研究malloc()Windows下的实现.但在我的研究中,我偶然发现了困扰我的事情:
首先,我知道在API级别,windows主要使用HeapAlloc()和VirtualAlloc()调用来分配内存.我从这里开始收集微软的实现malloc()(包含在CRT中 - C运行时)基本上要求HeapAlloc()块> 480字节,否则管理VirtualAlloc()为小分配分配的特殊区域,以防止碎片.
那一切都很好,很好.但是还有其他一些实现malloc(),例如nedmalloc,它声称比微软快了125%malloc.
所有这些让我想到了一些事情:
为什么我们不能只召唤HeapAlloc()小块?在碎片方面表现不佳(例如通过"先适合"而不是"最适合")?
是什么nedmalloc比微软更快malloc?
从上面的内容来看,我的印象是HeapAlloc()/ VirtualAlloc()速度太慢,以至于malloc()只是偶尔调用一次然后管理分配的内存本身要快得多.这个假设是真的吗?或者是malloc()因为碎片而需要的"包装"?有人会认为像这样的系统调用会很快 - 或者至少会有一些想法被放入其中以使它们有效.
平均而言,典型malloc调用执行了多少(一个数量级)的内存读/写(可能是已分配段数的函数)?我会直观地说它是一个普通程序的十位,我是对的吗?
windows malloc memory-management dynamic-memory-allocation nedmalloc
因此,我想我已经在网络上进行了彻底的搜索,发现没有什么真正有用的(最多只是令人困惑……)。
我想知道如何(如果可能)将Qt与非动态内存配合使用。我面临的问题是,对于许多小部件,我确切地知道我想要使用什么(这些子小部件,这些布局,固定数量等)。但是,当您不使用动态内存时,Qt中的所有内容似乎都会受到影响。一个简单的示例是QLayout,它来自Qt文档,旨在对所添加内容的所有权。所以基本上,下面的代码:
//In header
class ThumbnailDialog : public QDialog
{
Q_OBJECT
public:
ThumbnailDialog(QWidget* parent = 0);
~ThumbnailDialog(void);
private:
QPushButton m_confirm;
QPushButton m_cancel;
QHBoxLayout m_buttonsLayout;
};
//Implementation of ctor
ThumbnailDialog::ThumbnailDialog(QWidget* parent):
QDialog(parent)
{
//...
m_buttonsLayout.addWidget(&m_confirm);
m_buttonsLayout.addWidget(&m_cancel);
//...
setLayout(&m_dialogLayout);
}
Run Code Online (Sandbox Code Playgroud)
...将最终(在MSVC上)导致调试断言失败,_BLOCK_TYPE_IS_VALID(pHead->nBlockUse)因为在ThumbnailDialogdtor中,布局试图删除按钮...显然不应该这样做。
因此,像“ Qt Expert”所提倡的那样,我是否被迫在所有地方都使用动态记忆(虽然提到了“堆”……)?这似乎是错误的,因为这阻止了RAII的使用(如果父子关系意味着将进行删除,那么我不能使用智能指针来执行此操作)。对于编译时已知的内容,诉诸动态内存也感觉非常错误……(但是我可能是错的,这只是我的感觉)。
所以:有没有一种方法可以使用Qt而不new为每个小部件/布局使用动态内存和s?
我正在学习C++中的动态内存.作为为任何数据类型动态分配和解除分配的标准方法,我学到的是,例如,
//For double,
double* pvalue1 = nullptr;
pvalue1 = new double;
*pvalue1 = 17.3;
delete pvalue1; //free up when I'm done
Run Code Online (Sandbox Code Playgroud)
但是,对于一个char数组,我了解到它的处理方式不同:
char* pvalue2 = nullptr;
pvalue2 = new char[6];
strncpy(pvalue2,"Hello",sizeof("Hello"));
std::cout << "Pointed-to value of pvalue2 is " << *pvalue2 << std::endl;
std::cout << "Value of pvalue2 is " << pvalue2 << std::endl;
delete [] pvalue2; //free up when I'm done
Run Code Online (Sandbox Code Playgroud)
然后,在命令提示符下:
Pointed-to value of pvalue2 is H
Value of pvalue2 is Hello
Run Code Online (Sandbox Code Playgroud)
pvalue2给出"指向"字符串文字而不是内存地址?不是"指针值"总是它指向的内存地址吗?我在阅读这篇文章时看到了这样的内容:“本文假设您至少已经基本了解并理解 GNU/Linux 系统中的内存映射是如何工作的,特别是堆栈中静态分配的内存与堆栈中动态分配的内存之间的区别堆。”
这让我很困惑,因为我认为堆栈和堆是动态分配的,意味着仅在必要时分配,而全局变量和在函数内部声明为“静态”的变量是静态分配的,意味着始终分配。
例如,如果我有
void f() {
int x = 1;
...
}
Run Code Online (Sandbox Code Playgroud)
仅当调用函数 f() 时,值 1 才会被放入堆栈,并且堆栈指针只会递增。同样,如果我有
void f() {
int x = malloc(1 * sizeof(int));
...
}
Run Code Online (Sandbox Code Playgroud)
仅当调用 f() 时才会分配堆内存。但是,如果我有“int x = 1;” 在程序的全局部分或“static int x = 1;” 在函数体内,每当我运行该程序时,该内存都将在数据部分中分配值为 1。
我对这一切有错吗?
c heap-memory dynamic-memory-allocation stack-memory static-allocation
我试图理解双指针(这是指针持有另一个指针)的内部形成一个指针数组.所以,我试图运行以下代码,通过试验malloc进行调试,看看它是如何工作的.我无法理解malloc(0)我的情况,但我的代码通过输出"Hello World"来工作.
什么是差异
pToCharsPointers = (char**) malloc(0);
Run Code Online (Sandbox Code Playgroud)
和
pToCharsPointers = (char**) malloc(2 * sizeof(char*));
Run Code Online (Sandbox Code Playgroud)
请有人澄清一下我的情况.
#include <stdio.h>
char **pToCharsPointers;
int main(void)
{
pToCharsPointers = (char**) malloc(0);
char* pToChars = "Hello";
*pToCharsPointers = pToChars;
*(pToCharsPointers + 1)= "World";
printf("%s %s\n", *(pToCharsPointers + 0), *(pToCharsPointers + 1));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
另外,如果有人能解释双指针如何与内存中的示例一起工作以进行可视化,我会非常感激,因为即使我试图在很多地方阅读此内容,我仍未能看到自己.
编辑:感谢大家分享您的答案,这真的有助于理解.当我打印它时,我得到了一个带有malloc(0)的有效指针,并且在多次尝试期间也可以解除引用它而没有问题.想了解它的工作原理.在我的情况下似乎未定义的行为实际上是预期的行为.
new int[0]在C ++中是允许的,但是std::allocator<int>().allocate(0)定义明确?更笼统地说,所有分配器都必须接受0作为分配参数吗?
编辑:阅读我测试了Visual Studio的答案后std::allocator:allocate(0)给nullptr
deallocate(nullptr, anything) 是点头。
因此,使用nullptr是一个很好的建议,但是标准不要求deallocate(nullptr, 0)是nop,请参见是否允许使用C ++ allocator :: deallocate(NULL,1)?
c++ memory-management allocator dynamic-memory-allocation language-lawyer
在开始我的问题之前,我要说的是,我知道我可以使用标准库或 gsl 库(例如std::Vector)轻松解决我的问题。但我正在尝试学习 C++ 和动态内存分配,所以我想知道是否有一种方法可以在不使用 Vector 或类似的东西的情况下解决它。
我有一个Layer类,其中包含创建对象时确定的多个神经元(通过动态内存分配):
class Layer {
private:
unsigned int _size;
const Neuron* _neurons;
public:
Layer(unsigned int size);
~Layer();
const Neuron* getNeuron(unsigned int index) const;
};
Layer::Layer(unsigned int size) {
_size = size;
_neurons = new Neuron[size];
}
const Neuron* Layer::getNeuron(unsigned int index) const {
Expects(index < _size);
return &_neurons[index];
}
Layer::~Layer() {
delete[] _neurons;
}
Run Code Online (Sandbox Code Playgroud)
现在的挑战是在Network课堂上:我需要创建一个 n 层网络,每个层包含不同数量的神经元(作为长度为 n 的数组传递):
class Network {
private:
unsigned int _nb_layers;
const Layer* …Run Code Online (Sandbox Code Playgroud) 我被教官说叫p = (int*)malloc(5 * sizeof(int))是不是动态内存分配,并且p=(int*)malloc(n * sizeof(int))是动态内存分配。
讲师正在谈论基本数据结构并教授数组。他曾告诉我们使用int arr[100]语法创建数组的传统方法,但随后他向我们介绍了 malloc。
据他说,由于内存大小不会改变,我猜它不是动态的。
从我可以从互联网上收集的信息来看,malloc在运行时分配内存,以及在运行时分配内存时的动态内存分配。所以我认为这两个malloc语句都是动态内存分配。我的推理有问题吗?
我注意到 C++ 中的字符串容量遵循以下模式:
以下是长度不超过 500 的字符串的字符串容量:
15
30
60
120
240
480
960
Run Code Online (Sandbox Code Playgroud)
使用以下 C++ 程序找到了容量:
#include <iostream>
#include <vector>
using namespace std;
string getstr(int len) {
string s = "";
for (int i=0; i<len; i++) {
s.append("1");
}
return s;
}
int main() {
vector<int> capacities;
int prevcap;
for (int i=0; i<500; i++) {
int cap = getstr(i).capacity();
if (cap > prevcap) {
capacities.push_back(cap);
prevcap = cap;
}
}
for (int i : capacities) {
cout …Run Code Online (Sandbox Code Playgroud) 在 C++ 中实现某些数据结构时,需要能够创建一个包含未初始化元素的数组。正因为如此,拥有
buffer = new T[capacity];
Run Code Online (Sandbox Code Playgroud)
不适合,因为new T[capacity]初始化数组元素,这并不总是可能的(如果 T 没有默认构造函数)或期望的(因为构造对象可能需要时间)。典型的解决方案是分配内存并使用placement new。
为此,如果我们知道元素的数量是已知的(或者至少我们有一个上限)并在堆栈上分配,那么,据我所知,可以使用对齐的字节或字符数组,然后使用std::launder访问成员。
alignas(T) std::byte buffer[capacity];
Run Code Online (Sandbox Code Playgroud)
但是,它只解决了栈分配的问题,并没有解决堆分配的问题。为此,我假设需要使用对齐新,并写这样的东西:
auto memory = ::operator new(sizeof(T) * capacity, std::align_val_t{alignof(T)});
Run Code Online (Sandbox Code Playgroud)
然后将其转换为std::byte*orunsigned char*或T*。
// not sure what the right type for reinterpret cast should be
buffer = reinterpret_cast(memory);
Run Code Online (Sandbox Code Playgroud)
但是,有几件事我不清楚。
reinterpret_cast<T*>(ptr)如果 ptr 指向可与 T 进行指针互转换的对象,则定义结果。(请参阅此答案或https://eel.is/c++draft/basic.types#basic.compound-3)了解更多详细信息。我假设,将其转换T*为无效,因为 T 不一定与 new 的结果是指针可互转换的。但是,它是否为char*或定义明确std::byte?new为有效的指针类型(假设它不是实现定义的)时,它是否被视为指向数组第一个元素的指针,或者只是指向单个对象的指针?虽然,据我所知,在实践中很少(如果有的话)很重要,但存在语义差异,pointer_type + integer …c++ memory-management void-pointers dynamic-memory-allocation reinterpret-cast
c++ ×6
c ×3
malloc ×3
pointers ×2
allocator ×1
arrays ×1
char ×1
constructor ×1
heap-memory ×1
memory ×1
nedmalloc ×1
qt ×1
stack-memory ×1
string ×1
windows ×1