C++自学笔记——动态创建对象

动态创建对象

1. 什么是动态创建对象?

在学习之前的知识点时,我们知道有静态存储期和自动存储期。 静态存储期 的对象在程序的整个生命周期内都存在,全局变量和static修饰的局部变量都属于这一类。自动存储期的对象 ,这些对象在函数或代码块的执行期间存在,函数结束时自动销毁。局部变量是典型的自动存储期对象,它们在函数内部定义,函数结束时自动释放。

那么有没有人为命令的可以存储或者删除的对象呢?那就是动态创建对象,它允许你在程序运行时根据需要动态分配和释放内存。在处理不确定数量的对象、延迟初始化或者管理大型资源时非常有用。

2. 如何动态创建对象呢?

  1. 动态创建对象是通过new运算符来分配内存,而delete运算符用于释放内存。
cpp 复制代码
#include <iostream>
using namespace std;

int main() {
    // 动态创建一个整数
    int* x = new int;  // 分配一个整数的内存

    // 给动态分配的整数赋值
    *x = 42;

    // 输出动态分配的整数
    cout << "Value: " << *x << endl;

    // 释放内存
    delete x;  // 释放内存

    return 0;
}

在内存中的动态变化是这样的:

  1. 动态创建对象有以下初始化的方法:

  2. 动态创建数组

如果需要动态创建一个数组,可以使用new[]和delete[]。

cpp 复制代码
#include <iostream>
using namespace std;

int main() {
    int size = 5;
    int* arr = new int[size];  // 动态分配一个整数数组

    // 给数组赋值
    for (int i = 0; i < size; i++) {
        arr[i] = i * 10;
    }

    // 输出数组内容
    for (int i = 0; i < size; i++) {
        cout << arr[i] << " ";
    }
    cout << endl;

    // 释放内存
    delete[] arr;  // 释放数组内存

    return 0;
}

3.动态对象的存储位置--堆

  • 堆(Heap)
    是一个动态分配的内存区域,主要用于存储程序运行时需要灵活管理的资源。堆的大小通常是动态的,可以根据需要分配和释放。
  • 堆的特点
    手动管理:堆上的内存分配和释放需要程序员手动管理(使用new和delete)。
    灵活大小:堆的大小可以动态扩展,适合存储大对象或动态数量的对象。
    生命周期可控:堆上的对象生命周期由程序员控制,可以跨越函数调用。
    访问速度较慢:堆的内存分配和释放速度比栈慢,因为需要额外的内存管理操作。

与之作为对比的栈存储区域,可以做一个简单的了解。

  • 栈(stack)

是一个后进先出(LIFO,Last In, First Out)的内存区域,主要用于存储函数调用的上下文信息和局部变量。栈的大小通常是固定的,由操作系统在程序启动时分配。

  • 栈的特点

自动管理:栈上的内存分配和释放是自动的,由编译器管理。

快速访问:栈的内存分配和释放速度非常快,因为它是连续的内存区域,且操作简单。

有限大小:栈的大小通常是有限的(例如几MB),不能动态扩展。

局部性:栈上的变量通常是函数内部的局部变量,生命周期与函数的调用相关。

4. 动态创建对象失败

如果由于内存空间不足,创建对象失败,通常会像下面这样处理:
抛出异常 :默认情况下,C++中的new操作符会在内存分配失败时抛出std::bad_alloc异常。这使得程序在遇到内存分配失败时能够及时发现并处理错误。C++通过try、throw和catch三个关键字实现异常处理。try块用于包裹可能会抛出异常的代码。当try块中的代码抛出异常时,程序会跳转到相应的catch块处理异常。throw语句用于抛出一个异常。异常可以是任何类型,通常使用标准异常类或自定义异常类。catch块用于捕获和处理异常。可以有多个catch块来处理不同类型的异常。

例如:

cpp 复制代码
// 循环动态创建数组对象(异常处理)

#include <new>
#include <iostream>

using namespace std;

int main() {
    cout << "循环创建元素个数为30000的double型数组。\n";

    while (true) {
        try {
            double* a = new double[30000];  // 创建数组
        } catch (bad_alloc) {
            cout << "数组创建失败,程序中断。\n";
            return 1;
        }
    }
}

返回空指针:在某些情况下,程序员可能不希望因为内存分配失败而中断程序的执行。这时可以使用std::nothrow来防止抛出异常,而是返回一个空指针。如果在创建对象时指定"(nothrow)",则也可以在不引起异常的情况下返回空指针,示例如下:

cpp 复制代码
// 循环动态创建数组对象(抑制异常发生)

#include <cstdlib>
#include <iostream>

using namespace std;

int main() {
    cout << "循环创建元素个数为30000的double型数组。\n";

    while (true) {
        double* a = new(nothrow) double[30000];  // 创建(抑制异常发生)

        if (a == NULL) {
            cout << "数组创建失败,程序中断。\n";
            return 1;
        }
    }
}

5. 使用void指针动态创建对象

void指针是一种特殊的指针,它可以指向任何数据类型。void指针的类型是void*。由于void指针不能直接访问它所指向的数据,因此需要进行类型转换。

cpp 复制代码
#include <iostream>
using namespace std;

int main() {
    int num = 42;
    void* ptr = &num;  // ptr指向num的地址

    // 通过类型转换访问数据
    cout << "Value: " << *static_cast<int*>(ptr) << endl;

    return 0;
}

在动态内存分配中,需要使用malloc和calloc等函数返回void*,再进行类型转换。malloc函数用于分配一块未初始化的内存。见下面例子。

cpp 复制代码
#include <iostream>
#include <cstdlib>  // 用于malloc和free
using namespace std;

int main() {
    // 动态分配一个整数
    int* ptrInt = static_cast<int*>(malloc(sizeof(int)));
    if (ptrInt != nullptr) {
        *ptrInt = 42;
        cout << "Integer value: " << *ptrInt << endl;
        free(ptrInt);  // 释放内存
    }

    // 动态分配一个字符数组
    char* ptrChar = static_cast<char*>(malloc(10 * sizeof(char)));
    if (ptrChar != nullptr) {
        strcpy(ptrChar, "Hello");
        cout << "String: " << ptrChar << endl;
        free(ptrChar);  // 释放内存
    }

    return 0;
}
cpp 复制代码
#include <iostream>
#include <cstdlib>  // 用于calloc和free
using namespace std;

int main() {
    // 动态分配一个整数数组
    int* ptrIntArray = static_cast<int*>(calloc(5, sizeof(int)));
    if (ptrIntArray != nullptr) {
        for (int i = 0; i < 5; i++) {
            ptrIntArray[i] = i * 10;
        }
        cout << "Integer array values: ";
        for (int i = 0; i < 5; i++) {
            cout << ptrIntArray[i] << " ";
        }
        cout << endl;
        free(ptrIntArray);  // 释放内存
    }

    // 动态分配一个字符数组
    char* ptrCharArray = static_cast<char*>(calloc(10, sizeof(char)));
    if (ptrCharArray != nullptr) {
        strcpy(ptrCharArray, "Hello");
        cout << "String: " << ptrCharArray << endl;
        free(ptrCharArray);  // 释放内存
    }

    return 0;
}
相关推荐
tkevinjd1 小时前
并查集(力扣1971)
算法·leetcode·图论·并查集
Dovis(誓平步青云)1 小时前
【数据结构】励志大厂版·初阶(复习+刷题):线性表(顺序表)
c语言·数据结构·经验分享·笔记·学习·算法·学习方法
是Dream呀1 小时前
深度学习算法:从基础到实践
人工智能·深度学习·算法
Y1nhl1 小时前
搜广推校招面经七十五
人工智能·深度学习·算法·机器学习·支持向量机·推荐算法·搜索算法
星火撩猿2 小时前
GIS开发笔记(5)结合osg及osgEarth实现虚线环形区域绘制
笔记
pumpkin845142 小时前
学习笔记十三—— 理解 Rust 闭包:从语法到 impl Fn vs Box<dyn Fn>
笔记·学习·rust
Brookty2 小时前
【算法】归并排序
数据结构·算法·排序算法
·醉挽清风·2 小时前
学习笔记—C++—模板初阶
开发语言·c++·笔记·学习
虾球xz3 小时前
游戏引擎学习第216天
服务器·c++·学习·游戏引擎
星星火柴9364 小时前
数据结构:哈希表 | C++中的set与map
数据结构·c++·笔记·算法·链表·哈希算法·散列表