手机可以建网站嘛建站好吗,机械做网站,wordpress 设置语言,wordpress 手机版菜单C中低级内存操作
C相较于C有一个巨大的优势#xff0c;那就是你不需要过多地担心内存管理。如果你使用面向对象的编程方式#xff0c;你只需要确保每个独立的类都能妥善地管理自己的内存。通过构造和析构#xff0c;编译器会帮助你管理内存#xff0c;告诉你什么时候需要进…C中低级内存操作
C相较于C有一个巨大的优势那就是你不需要过多地担心内存管理。如果你使用面向对象的编程方式你只需要确保每个独立的类都能妥善地管理自己的内存。通过构造和析构编译器会帮助你管理内存告诉你什么时候需要进行内存操作。将内存管理隐藏在类中显著提高了可用性这一点在标准库类中得到了很好的体现。
然而在某些应用程序或遗留代码中你可能会遇到需要更低级别地操作内存的情况。无论是出于遗留代码、效率、调试还是好奇心了解如何操作原始字节总是有帮助的。
指针
C编译器会使用指针的声明类型来允许你进行指针算术。如果你声明了一个指向整数的指针并将其增加1那么这个指针在内存中前进的距离是整数的大小而不是一个单一的字节。这种操作对数组最有用因为数组包含的数据是类型一致且在内存中连续的。
例如假设你在自由存储区声明了一个整数数组
int* myArray { new int[8] };你可能已经熟悉了以下用于设置索引为2的值的语法
myArray[2] 33;通过使用指针算术你也可以使用以下等效的语法该语法获取到myArray“向前两个整数”处的内存的指针然后解引用它以设置该值
*(myArray 2) 33;作为访问单个元素的另一种语法指针算术看起来可能不太吸引人。但其真正的力量在于像myArray2这样的表达式仍然是一个指向整数的指针因此可以表示一个更小的整数数组。
让我们通过一个使用宽字符串的例子来看看。宽字符串支持所谓的Unicode字符以表示例如日语字符串。wchar_t类型是一个可以容纳这种Unicode字符的字符类型并且通常比char要大也就是说它不仅仅是一个字节。要告诉编译器一个字符串字面量是一个宽字符串字面量可以在其前面加上一个L。
例如假设你有以下宽字符串
const wchar_t* myString { LHello, World };进一步假设你有一个函数该函数接受一个宽字符串并返回一个包含输入字符串大写版本的新字符串
wchar_t* toCaps(const wchar_t* text);请记住C风格的字符串是以零结尾的即它们的最后一个元素包含\0。因此没有必要在函数中添加一个大小参数来指定输入字符串的长度。该函数只需不断地迭代字符串的各个字符直到遇到\0字符为止。
通过将myString传递给toCaps()函数你可以将其全部转换为大写。然而如果你只想部分地大写化myString你可以使用指针算术来仅引用字符串的后一部分。下面的代码通过仅向指针加7来调用toCaps()函数以处理宽字符串中的“World”部分尽管wchar_t通常超过1个字节
toCaps(myString 7);另一个有用的指针算术应用涉及到减法。从同一类型的另一个指针中减去一个指针会给你两个指针之间指向类型的元素数量而不是它们之间的绝对字节数。
自定义内存管理
在你将遇到的99%有人可能会说100%的情况中C中的内置内存分配功能是足够的。在幕后new和delete完成了以适当大小的块分配内存、维护可用内存区域列表以及在删除时将内存块释放回该列表的所有工作。但是当资源约束非常紧张或者在非常特殊的条件下例如管理共享内存实施自定义内存管理可能是一个可行的选项。不用担心这并不像听起来那么可怕。
基本上自己管理内存意味着类会分配一大块内存并根据需要将该内存分配出去。这种方法有什么好处呢管理自己的内存可能会减少开销。当你使用new来分配内存时程序还需要预留一小部分空间以记录分配了多少内存。这样当你调用delete时可以释放适当数量的内存。对于大多数对象开销比分配的内存小得多因此影响甚微。然而对于小对象或有大量对象的程序开销可能会产生影响。当你自己管理内存时你可能会提前知道每个对象的大小因此你可能能够避免每个对象的开销。对于大量的小对象来说差异可能是巨大的。
执行自定义内存管理需要重载new和delete操作符。
垃圾收集
在支持垃圾收集的环境中程序员很少如果有的话明确释放与对象关联的内存。相反不再有任何引用的对象将在某个时候被运行时库自动清理。垃圾收集没有像在C#和Java中那样内置到C语言中。在现代C中你使用智能指针来管理内存而在遗留代码中你将看到通过new和delete在对象级别进行内存管理。
诸如shared_ptr这样的智能指针提供了与垃圾收集内存非常相似的东西也就是说当某一资源的最后一个shared_ptr实例被销毁时该资源也会在那个时刻被销毁。在C中实现真正的垃圾收集是可能但不容易的但释放自己从释放内存的任务中可能会引入新的问题。
标记-清除垃圾收集
一种垃圾收集的方法被称为“标记-清除”Mark and Sweep。在这种方法下垃圾收集器会周期性地检查程序中的每一个指针并标注哪些内存仍然在使用中。在周期结束时任何没有被标记的内存被认为是不再使用的并会被释放。在C中实现这样的算法并不简单如果做错了可能比使用delete更容易出错
尽管在C中已经有了安全且简单的垃圾收集机制的尝试但即使有了完美的C垃圾收集实现也不一定适用于所有应用程序。垃圾收集的缺点包括
当垃圾收集器正在运行时程序可能变得无响应。在使用垃圾收集器的情况下你会遇到所谓的“非确定性析构函数”。因为一个对象在被垃圾收集之前不会被销毁所以析构函数在对象离开其作用域时不会立即执行。这意味着由析构函数完成的资源清理例如关闭文件、释放锁等直到未来某个不确定的时间才会被执行。
编写垃圾收集机制是非常困难的。你很可能会做错而且很可能会很慢。因此如果你确实想在你的应用程序中使用垃圾收集内存我强烈建议你研究现有的专门的垃圾收集库并重用它们。
对象池
垃圾收集就像是为野餐购买盘子并将用过的盘子留在院子里以便某人在某个时候将它们捡起来并扔掉。肯定有更环保的内存管理方法。对象池就是回收的等价物。你购买了一定数量的盘子使用过一个盘子后你将其清洗以便以后可以再次使用。
对象池是理想的解决方案适用于你需要在一段时间内多次使用相同类型的多个对象并且每次创建都会产生开销的情况。