网站首页 > 基础教程 正文
为了提高程序的性能,一个做法是一次性分配足够多的内存,从而避免多次申请以及数据拷贝。对于c++,有一个问题:如何在已分配好的内存上构造对象?
小伙伴提到使用reserve预先分配内存,再push_back或emplace_back,存储过万个大对象时可极大提升效率。探究其实现原理,会发现分配内存简单,调用标准库或者nedmalloc、tcmalloc等库中的函数即可;有了内存,问题同样变成如何在已分配的内存上构造对象?
方案
有两种解决方案解决这个问题。
(1)placement new
第一种方案是使用placement new。其用法过程为:首先分配足够大的内存;然后用placement new语法生成对象:new(ptr) xxx(),其中ptr是足够容纳所指对象的指针。
一个使用例子:
class Person {
private:
int age;
std::string name;
public:
// methods
};
int main(int argc, char** argv) {
char mem[sizeof(Person)]; // 或者 auto mem = malloc(sizeof(Person));
auto p = new(mem) Person();
assert((void*)p == (void*)mem); // 两个指针指向同一块内存
return 0;
}
使用placement new有三个注意点:一是要有足够的内存放置对象,这是必须的;二是指针应该是“对齐”的,例如对于4字节对齐的系统,指针地址应该是4的整数倍;三是你(可能)需要显式调用析构函数完成对象的销毁。
(2)operator new
使用new生成对象实际上执行了三个操作:
①调用operator new分配内存
②调用类的构造函数
③返回指针
其中operator new是可重载的,无论全局还是特定类。其函数原型为:
void* operator new(size_t sz);
回到把对象在指定内存上构造的问题上,我们可以通过重载operator new,返回已分配内存的指针。然而由于operator new函数只接受一个参数,地址指针需要是“全局”变量才能生效。这样想来,这种方案实用性并不高。
其他
如果你希望像vector中的reserve先分配内存,然后在其上装载对象,可以使用allocator。allocator定义在头文件中,能对指定类型分配合适的内存,并可手动调用对象的构造函数和析构函数。
用法示例:
int main(int argc, char** argv) {
std::allocator<Person> alloc;
auto p = alloc.allocate(1); // 分配一个Person对象的内存
alloc.construct(p); // 调用Person的构造函数,如果构造函数有参数,参数写在p之后
// p 现在是一个指向Person的指针,且其指向对象被初始化过
// 对p进行一些操作
// 销毁对象,但不释放内存,等同于调用p->~Person()
alloc.destroy(p);
// 释放内存
alloc.deallocate(p, 1);
return 0;
}
对于可以内部管理的情形,建议使用allocator而非placement new。
作用
为什么有这个需求呢?个人觉得有三方面的原因:
像vector的reserve,预先分配内存可大幅提高性能;
重复利用已分配好的空间,避免内存碎片;
细粒度进行内存管理,例如能够实现许多虚拟机中的将内存数据从一个片区转移到另一个片区(垃圾回收时触发)。
写在最后:对于准备学习C/C++编程的小伙伴,如果你想更好的提升你的编程核心能力(内功)不妨从现在开始!
编程学习书籍分享:
编程学习视频分享:
整理分享(多年学习的源码、项目实战视频、项目笔记,基础入门教程)
欢迎转行和学习编程的伙伴,利用更多的资料学习成长比自己琢磨更快哦!
对于C/C++感兴趣可以关注小编在后台私信我:【编程交流】一起来学习哦!可以领取一些C/C++的项目学习视频资料哦!已经设置好了关键词自动回复,自动领取就好了!
猜你喜欢
- 2024-10-12 全面剖析 C++ Boost 智能指针!| CSDN 博文精选
- 2024-10-12 C++设计模式——原型模式 设计模式之原型模式
- 2024-10-12 如何攻克 C++ 中复杂的类型转换? c++中四种类型转换的方式
- 2024-10-12 C++|由成员函数到运算符重载(类内、类外、友元方式重载)
- 2024-10-12 C++11新特性(49)- 用移动类对象代替拷贝类对象
- 2024-10-12 C++类的默认成员函数 c++类中定义的成员默认访问属性为( )
- 2024-10-12 C++的23种设计模式(上篇-创建型模式)
- 2024-10-12 C++构造函数和析构函数详解 c语言构造函数和析构函数
- 2024-10-12 c++——默认成员函数 c++成员变量默认值
- 2024-10-12 C++|类中实现操作符重载,用操作符代替成员函数名
- 05-162025前端最新面试题之HTML和CSS篇
- 05-16大数据开发基础之HTML基础知识
- 05-16微软专家告诉你Win10 Edge浏览器和EdgeHTML的区别
- 05-16快速免费将网站部署到公网方法(仅支持HTML,CSS,JS)
- 05-16《从零开始学前端:HTML+CSS+JavaScript的黄金三角》
- 05-16一个简单的标准 HTML 设计参考
- 05-16css入门
- 05-16前端-干货分享:更牛逼的CSS管理方法-层(CSS Layers)
- 最近发表
- 标签列表
-
- jsp (69)
- pythonlist (60)
- gitpush (78)
- gitreset (66)
- python字典 (67)
- dockercp (63)
- gitclone命令 (63)
- dockersave (62)
- linux命令大全 (65)
- pythonif (86)
- location.href (69)
- dockerexec (65)
- deletesql (62)
- c++模板 (62)
- linuxgzip (68)
- 字符串连接 (73)
- nginx配置文件详解 (61)
- html标签 (69)
- c++初始化列表 (64)
- mysqlinnodbmyisam区别 (63)
- arraylistadd (66)
- console.table (62)
- mysqldatesub函数 (63)
- window10java环境变量设置 (66)
- c++虚函数和纯虚函数的区别 (66)