c++笔记 用new和delete从栈区申请空间、静态成员

2024-04-21 13:08

本文主要是介绍c++笔记 用new和delete从栈区申请空间、静态成员,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、new与delete和malloc、calloc、realloc比较

1.malloc等返回一个void指针,c++不允许将void赋值给其他任何指针,必须强转。

1.2、malloc等可能申请内存失败,所以必须判断返回值来确保内存分配成功。

1.3、malloc等不会调用构造函数。free 不会调用析构函数(重要)

二、

C++中解决动态内存分配的方案是把创建一个对象所需要的操作都结合在一个称为 new 的运算符里。当用 new 创建一个对象时,它就在堆里为对象分配内存并调用 构造函数完成初始化。
 

Person* person = new Person;

等价于

Person* person = (Person*)malloc(sizeof(Person));
if(person == NULL){
return 0;
}

New 操作符能确定在调用构造函数初始化之前内存分配是成功的,所有不用显式 确定调用是否成功。 现在我们发现在堆里创建对象的过程变得简单了,只需要一 个简单的表达式,它带有内置的长度计算、类型转换和安全检查。这样在堆创建一 个对象和在栈里创建对象一样简单 

new 表达式的反面是 delete 表达式。delete 表达式先调用析构函数,然后释放内 存。正如 new 表达式返回一个指向对象的指针一样,delete 需要一个对象的地 址。 delete 只适用于由 new 创建的对象。 如果使用一个由 malloc 或者 calloc 或 者 realloc 创建的对象使用 delete,这个行为是未定义的。因为大多数 new 和 delete 的实现机制都使用了 malloc 和 free,所以很可能没有调用析构函数就释放了内存。 如果正在删除的对象的指针是 NULL,将不发生任何事,因此建议在删除指针后,立 即把指针赋值为 NULL,以免对它删除两次,对一些对象删除两次可能会产生某些 问题

class Person{
public:
Person(){
cout << "无参构造函数!" << endl;
pName = (char*)malloc(strlen("undefined") + 1);
strcpy(pName, "undefined");
mAge = 0;
}
Person(char* name, int age){
cout << "有参构造函数!" << endl;
pName = (char*)malloc(strlen(name) + 1);
strcpy(pName, name);
mAge = age;
}
void ShowPerson(){
cout << "Name:" << pName << " Age:" << mAge << endl;
}
~Person(){
cout << "析构函数!" << endl;
if (pName != NULL){
delete pName;
pName = NULL;
}
}
public:
char* pName;
int mAge;
};
void test(){
Person* person1 = new Person;
Person* person2 = new Person("John",33);
person1->ShowPerson();
person2->ShowPerson();
delete person1;
delete person2;
}

三、delete void*可能会出错

如果对一个 void*指针执行delete操作,这将可能成为一个程序错误,除非指针指 向的内容是非常简单的,因为它将不执行析构函数.以下代码未调用析构函数,导致可用内存减少。

class Person{
public:
Person(char* name, int age){
pName = (char*)malloc(sizeof(name));
strcpy(pName,name);
mAge = age;
}
~Person(){
if (pName != NULL){
delete pName;
}
}
public:
char* pName;
int mAge;
};
void test(){
void* person = new Person("john",20);
delete person;
}

malloc、free 和 new、delete 不可以混搭使用吗?也就是说 malloc 分配的内 存,不可以调用 delete。 通过 new 创建的对象,不可以调用 free 来释放。

四、静态成员

在一个类中,若将一个成员变量声明为 static,这种成员称为静态成员变量。与一 般的数据成员不同,无论建立了多少个对象,都只有一个静态数据的拷贝。静态成 员变量,属于某个类,所有对象共享。 静态变量,是在编译阶段就分配空间,对 象还没有创建时,就已经分配空间。 静态成员变量必须在类中声明,在类外定义。 静态数据成员不属于某个对象,在 为对象分配空间中不包括静态成员所占空间。 静态数据成员可以通过类名或者对 象名来引用。

class Person{
public:
//普通成员函数可以访问 static 和 non-static 成员属性
void changeParam1(int param){
mParam = param;
sNum = param;
}
//静态成员函数只能访问 static 成员属性
static void changeParam2(int param){
//mParam = param; //无法访问
sNum = param;
}
private:
static void changeParam3(int param){
//mParam = param; //无法访问
sNum = param;
}
public:
int mParam;
static int sNum;
};
//静态成员属性类外初始化
int Person::sNum = 0;
int main(){
//1. 类名直接调用
Person::changeParam2(100);
//2. 通过对象调用
Person p;
p.changeParam2(200);
//3. 静态成员函数也有访问权限
//Person::changeParam3(100); //类外无法访问私有静态成员函数
//Person p1;
//p1.changeParam3(200);
return EXIT_SUCCESS;
}

成员:成员变量 成员函数 static 修饰成员变量 修饰成员函数 static声明为静态的,称为静态成员。 不管这个类创建了多少个对象,静态成员只有一个拷 贝,这个拷贝被所有属于这个类的对象共享。 静态成员 属于 而不是对象。

 静态变量,是在编译阶段就分配空间,对象还没有创建时,就已经分配空间。 静态成员变量必须在类中声明,在类外定义。 静态数据成员不属于某个对象,在为对象分配空间中不包括静态成员所占空间。

五、静态成员函数

1、静态成员函数的目的 操作静态成员数据。

2、静态成员函数 不能访问 非静态成员数据。(静态成员函数内部没有this指针)

3、普通成员函数 可以操作 静态成员数据 非静态成员数据。

4、静态成员变量 和 静态成员函数 都有权限之分。

class Person{
public:
//普通成员函数可以访问 static 和 non-static 成员属性
void changeParam1(int param){
mParam = param;
sNum = param;
}
//静态成员函数只能访问 static 成员属性
static void changeParam2(int param){
//mParam = param; //无法访问
sNum = param;
}
private:
static void changeParam3(int param){
//mParam = param; //无法访问
sNum = param;
}
public:
int mParam;
static int sNum;
};
//静态成员属性类外初始化
int Person::sNum = 0;
int main(){
//1. 类名直接调用
Person::changeParam2(100);
//2. 通过对象调用
Person p;
p.changeParam2(200);
//3. 静态成员函数也有访问权限
//Person::changeParam3(100); //类外无法访问私有静态成员函数
//Person p1;
//p1.changeParam3(200);
return EXIT_SUCCESS;
}

这篇关于c++笔记 用new和delete从栈区申请空间、静态成员的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/923154

相关文章

C++统计函数执行时间的最佳实践

《C++统计函数执行时间的最佳实践》在软件开发过程中,性能分析是优化程序的重要环节,了解函数的执行时间分布对于识别性能瓶颈至关重要,本文将分享一个C++函数执行时间统计工具,希望对大家有所帮助... 目录前言工具特性核心设计1. 数据结构设计2. 单例模式管理器3. RAII自动计时使用方法基本用法高级用法

Three.js构建一个 3D 商品展示空间完整实战项目

《Three.js构建一个3D商品展示空间完整实战项目》Three.js是一个强大的JavaScript库,专用于在Web浏览器中创建3D图形,:本文主要介绍Three.js构建一个3D商品展... 目录引言项目核心技术1. 项目架构与资源组织2. 多模型切换、交互热点绑定3. 移动端适配与帧率优化4. 可

深入解析C++ 中std::map内存管理

《深入解析C++中std::map内存管理》文章详解C++std::map内存管理,指出clear()仅删除元素可能不释放底层内存,建议用swap()与空map交换以彻底释放,针对指针类型需手动de... 目录1️、基本清空std::map2️、使用 swap 彻底释放内存3️、map 中存储指针类型的对象

Go之errors.New和fmt.Errorf 的区别小结

《Go之errors.New和fmt.Errorf的区别小结》本文主要介绍了Go之errors.New和fmt.Errorf的区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考... 目录error的基本用法1. 获取错误信息2. 在条件判断中使用基本区别1.函数签名2.使用场景详细对

C++ STL-string类底层实现过程

《C++STL-string类底层实现过程》本文实现了一个简易的string类,涵盖动态数组存储、深拷贝机制、迭代器支持、容量调整、字符串修改、运算符重载等功能,模拟标准string核心特性,重点强... 目录实现框架一、默认成员函数1.默认构造函数2.构造函数3.拷贝构造函数(重点)4.赋值运算符重载函数

C++ vector越界问题的完整解决方案

《C++vector越界问题的完整解决方案》在C++开发中,std::vector作为最常用的动态数组容器,其便捷性与性能优势使其成为处理可变长度数据的首选,然而,数组越界访问始终是威胁程序稳定性的... 目录引言一、vector越界的底层原理与危害1.1 越界访问的本质原因1.2 越界访问的实际危害二、基

Python学习笔记之getattr和hasattr用法示例详解

《Python学习笔记之getattr和hasattr用法示例详解》在Python中,hasattr()、getattr()和setattr()是一组内置函数,用于对对象的属性进行操作和查询,这篇文章... 目录1.getattr用法详解1.1 基本作用1.2 示例1.3 原理2.hasattr用法详解2.

c++日志库log4cplus快速入门小结

《c++日志库log4cplus快速入门小结》文章浏览阅读1.1w次,点赞9次,收藏44次。本文介绍Log4cplus,一种适用于C++的线程安全日志记录API,提供灵活的日志管理和配置控制。文章涵盖... 目录简介日志等级配置文件使用关于初始化使用示例总结参考资料简介log4j 用于Java,log4c

C++归并排序代码实现示例代码

《C++归并排序代码实现示例代码》归并排序将待排序数组分成两个子数组,分别对这两个子数组进行排序,然后将排序好的子数组合并,得到排序后的数组,:本文主要介绍C++归并排序代码实现的相关资料,需要的... 目录1 算法核心思想2 代码实现3 算法时间复杂度1 算法核心思想归并排序是一种高效的排序方式,需要用

通过配置nginx访问服务器静态资源的过程

《通过配置nginx访问服务器静态资源的过程》文章介绍了图片存储路径设置、Nginx服务器配置及通过http://192.168.206.170:8007/a.png访问图片的方法,涵盖图片管理与服务... 目录1.图片存储路径2.nginx配置3.访问图片方式总结1.图片存储路径2.nginx配置