0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

类和动态内存分配(一)

冬至配饺子 来源:iDoitnow 作者:艰默 2023-07-18 10:45 次阅读

1. 静态类成员函数

如果将成员函数声明为静态的(函数声明必须包含关键字static,但如果函数定义是独立的,则其中不能包含关键字static),则不能通过对象调用静态成员函数,且由于静态成员函数不能与特定的对象相关联,因此静态成员函数只能使用静态数据成员。

2. 在构造函数中使用new时应注意的事项

  • 如果在构造函数中使用new来初始化指针成员,则应在析构函数中使用delete
  • new和delete必须相互兼容,new对应delete,new[]对应delete[]。
  • 如果有多个构造函数,则必须以相同的方式使用new,要么都带,要么都不带。(因为只有一个析构函数,所有构造函数必须与其兼容)
  • 应定义一个复制构造函数,通过深度复制将一个对象初始化为另外一个对象。(具体地说,复制构造函数应分配足够的空间来存储复制的数据,并复制数据,而不仅仅是数据的地址,同时,若果有受影响的静态成员,要及时在复制构造函数中更新该静态成员)
  • 应当定义一个赋值运算符,通过深度复制一个对象给另外一个对象。(同时需要检查自我赋值的情况,释放成员指针以前指向的内存,复制数据而不仅仅是数据的地址,并返回一个指向调用对象的引用)。

3. 有关函数返回对象的说明

当成员函数或独立的函数返回对象时,常用的方式有:

3.1 返回指向const对象的引用

使用const引用的主要原因是为了提高效率,但该方式存在一定的限制。如果函数返回(通过调用对象的方法或将对象作为参数)传递给它的对象,可以通过返回引用来提高效率。

3.2 返回指向非const对象的引用

两种常见的返回非const对象情形是,重载赋值运算符以及重载与cout一起使用的<<运算符。前者这样做是为了提高效率,而后者必须这么做。

3.3 返回对象

当被返回的对象是被调用函数中的局部变量,则应该返回对象。

3.4 返回从const对象

返回const对象可以避免类似force1 + force2 = net这种奇异属性误用可能带来的错误。

总的来说,如果方法或函数要返回局部对象,则应该返回对象。如果方法或函数要返回一个没有公有复制构造函数的类(如ostream类)的对象,则必须返回一个指向这个对象的引用。如果方法或函数可以返回对象,也可以返回对象的引用,则优先选择引用,提高效率。

4. new与delete

定位new运算符能够让使用者在分配内存时能够指定内存位置。但这种运算符在应用于对象的时候,应该注意:delete可以与常规的new运算符配合使用,但不能与定位new运算符配合使用。原因见下例:

// placenew1.cpp -- new, placement new, no delete
#include < iostream >
#include < new >
#include < string >
using namespace std;
const int BUF = 512;
class JustTesting
{
private:
    string words;
    int number;

public:
    JustTesting(const string &s = "Just Testing", int n = 0)
    {
        words = s;
        number = n;
        cout < < words < < " constructedn";
    }
    ~JustTesting() { cout < < words < < " destroyedn"; }
    void Show() const { cout < < words < < ", " < < number < < endl; }
};
int main()
{
    char *buffer = new char[BUF]; // get a block of memory
    JustTesting *pc1, *pc2;
    pc1 = new (buffer) JustTesting;     // place object in buffer
    pc2 = new JustTesting("Heap1", 20); // place object on heap
    cout < < "Memory block addresses:n"
         < < "buffer: "
         < < (void *)buffer < < " heap: " < < pc2 < < endl;
    cout < < "Memory contents:n";
    cout < < pc1 < < ": ";
    pc1- >Show();
    cout < < pc2 < < ": ";
    pc2- >Show();
    JustTesting *pc3, *pc4;
    pc3 = new (buffer) JustTesting("Bad Idea", 6);
    pc4 = new JustTesting("Heap2", 10);
    cout < < "Memory contents:n";
    cout < < pc3 < < ": ";
    pc3- >Show();
    cout < < pc4 < < ": ";
    pc4- >Show();
    delete pc2;      // free Heap1
    delete pc4;      // free Heap2
    delete[] buffer; // free buffer
    cout < < "Donen";
    return 0;
}

其中,使用new运算符创建了一个512字节的内存缓存区,然后在使用new运算符在堆中创建两个JustTesting对象。并试图使用定位new运算符在内存缓冲区创建两个JustTesting对象,最后在使用delete来释放new分配的内存时出现异常,上述代码的输出如下:

Just Testing constructed
Heap1 constructed
Memory block addresses:
buffer: 00320AB0 heap: 00320CE0
Memory contents:
00320AB0: Just Testing, 0
00320CE0: Heap1, 20
Bad Idea constructed
Heap2 constructed
Memory contents:
00320AB0: Bad Idea, 6
00320EC8: Heap2, 10
Heap1 destroyed
Heap2 destroyed
Done

根据打印信息,很明显发现pc1pc3的析构函数未被正常调用,且pc3在创建的时候,直接覆盖了pc1的内存。

在使用定位new运算符时,要注意一下两点:

  • 要保证每个对象要使用不同的内存单元(即需要提供两个不同的内存地址,并确保两个内存单元不存在重叠)。
  • 如果使用定位new运算符来为对象分配内存,必须保证其析构函数能够正常的被调用(delete可以和常规的new运算符配合使用,但不能与定位new运算符配合使用,因此,delete对于定位new运算符对其分配内存做了什么一无所知)。

修改后的代码:

// placenew2.cpp -- new, placement new, no delete
#include < iostream >
#include < new >
#include < string >
using namespace std;
const int BUF = 512;
class JustTesting
{
private:
    string words;
    int number;

public:
    JustTesting(const string &s = "Just Testing", int n = 0)
    {
        words = s;
        number = n;
        cout < < words < < " constructedn";
    }
    ~JustTesting() { cout < < words < < " destroyedn"; }
    void Show() const { cout < < words < < ", " < < number < < endl; }
};
int main()
{
    char *buffer = new char[BUF]; // get a block of memory
    JustTesting *pc1, *pc2;
    pc1 = new (buffer) JustTesting;     // place object in buffer
    pc2 = new JustTesting("Heap1", 20); // place object on heap
    cout < < "Memory block addresses:n"
         < < "buffer: "
         < < (void *)buffer < < " heap: " < < pc2 < < endl;
    cout < < "Memory contents:n";
    cout < < pc1 < < ": ";
    pc1- >Show();
    cout < < pc2 < < ": ";
    pc2- >Show();
    JustTesting *pc3, *pc4;
    // fix placement new location
    pc3 = new (buffer + sizeof(JustTesting))
        JustTesting("Better Idea", 6);
    pc4 = new JustTesting("Heap2", 10);
    cout < < "Memory contents:n";
    cout < < pc3 < < ": ";
    pc3- >Show();
    cout < < pc4 < < ": ";
    pc4- >Show();
    delete pc2; // free Heap1
    delete pc4; // free Heap2
    // 显式销毁放置的新对象 
    pc3- >~JustTesting(); // destroy object pointed to by pc3
    pc1- >~JustTesting(); // destroy object pointed to by pc1
    delete[] buffer;     // free buffer
    cout < < "Donen";
    return 0;
}

其对应的输出:

Just Testing constructed
Heap1 constructed
Memory block addresses:
buffer: 00320AB0 heap: 00320CE0
Memory contents:
00320AB0: Just Testing, 0
00320CE0: Heap1, 20
Better Idea constructed
Heap2 constructed
Memory contents:
00320AD0: Better Idea, 6
00320EC8: Heap2, 10
Heap1 destroyed
Heap2 destroyed
Better Idea destroyed
Just Testing destroyed
Done

对于使用定位new运算符创建的对象,由于晚创建的对象可能依赖于早创建的对象,所以在删除时应以与创建顺序相反的顺序进行删除。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 存储器
    +关注

    关注

    38

    文章

    7148

    浏览量

    161990
  • 按位运算符
    +关注

    关注

    0

    文章

    3

    浏览量

    4763
收藏 人收藏

    评论

    相关推荐

    C语言知识总结:动态内存分配

    动态内存分配就 是指在程序执行的过程中动态分配或者回收存储空间的分配内存的方法。
    发表于 10-24 15:52 654次阅读

    使用C语言实现简单动态内存分配

    首先要明白为何需要动态内存分配,熟悉C语言的读者应该对这个比较熟悉,需要一段内存时会使用malloc函数来申请所需要大小的内存,函数返回一段内存
    发表于 07-28 16:26 391次阅读
    使用C语言实现简单<b class='flag-5'>动态内存</b><b class='flag-5'>分配</b>

    C语言程序设计中动态内存分配如何实现

    C语言程序设计中,动态内存分配如何实现,需要注意哪些问题?
    发表于 09-28 16:53 850次阅读

    基于Core的动态内存分配方案

    为了解决基于C*Core系列芯片嵌入式开发过程中,C*Core系统在某些情况下由于受操作系统、数据格式差异等因素影响,不能动态分配C*Core系列芯片内存的问题,采用数组与标志位相结合的
    发表于 07-11 10:37 38次下载
    基于Core的<b class='flag-5'>动态内存</b><b class='flag-5'>分配</b>方案

    基于μCOS-II的TLSF动态内存分配算法的应用与仿真

    以嵌入式实时系统为背景,深入研究了TLSF动态内存分配算法原理及实现过程,并将TLSF移植到COS-II中,进行了基于x86平台的仿真测试,取得了很好的效果,为以后学习和应用TLSF算法提供
    发表于 09-25 10:42 44次下载

    动态内存分配举例,以及动态数组的构造

    1:malloc是由程序员在堆栈动态开辟空间 2:返回值开辟空间的首地址,但是类型是void *,需要强制类型转换 3:分配内存空间应该能整除类型所占的字节数 4:包含头文件malloc.h
    的头像 发表于 07-10 16:41 6975次阅读
    <b class='flag-5'>动态内存</b><b class='flag-5'>分配</b>举例,以及<b class='flag-5'>动态</b>数组的构造

    C语言动态内存分配分析

    将原来动态开辟的动态内存重新开辟一个字节数,如果这个数比以前的大,前面的数据保存。如果比原来的小,保留前面的数据。
    的头像 发表于 01-07 11:02 4041次阅读
    C语言<b class='flag-5'>动态内存</b><b class='flag-5'>分配</b>分析

    单片机系统进行动态内存分配和任务调度思想的资料和代码实例说明

    内存分配设计思想:我们设置动态内存分配的初衷在于:有些单片机系统内存资源比较少,便显得特别珍贵,因此我们要实现
    发表于 09-30 17:13 4次下载
    单片机系统进行<b class='flag-5'>动态内存</b><b class='flag-5'>分配</b>和任务调度思想的资料和代码实例说明

    嵌入式中需要用到动态内存

    所谓动态内存分配(Dynamic Memory Allocation)就是指在程序执行的过程中动态分配或者回收存储空间的分配
    的头像 发表于 07-27 08:11 2863次阅读

    嵌入式C语言中的动态内存管理和动态内存分配

    动态内存管理同时还具有一个优点:当程序在具有更多内存的系统上需要处理更多数据时,不需要重写程序。
    发表于 08-15 17:16 1980次阅读

    动态内存分配的注意事项及本质是什么

    C语言中比较重要的就是指针,它可以用来链表操作,谈到链表,很多时候为此分配内存采用动态分配而不是静态分配。 本文分享自华为云社区《 【云驻共创】C语言中
    的头像 发表于 10-13 15:37 3112次阅读
    <b class='flag-5'>动态内存</b><b class='flag-5'>分配</b>的注意事项及本质是什么

    【STM32H7教程】第27章 STM32H7的TCM,SRAM等五块内存动态内存分配实现

    动态内存分配实现本章教程为大家分享一种DTCM,SRAM1,SRAM2,SRAM3和SRAM4可以独立管理的动态内存管理方案,在实际项目中有一定的实用价值,比如MP3编解码,JPEG...
    发表于 12-16 16:53 8次下载
    【STM32H7教程】第27章       STM32H7的TCM,SRAM等五块<b class='flag-5'>内存</b>的<b class='flag-5'>动态内存</b><b class='flag-5'>分配</b>实现

    嵌入式开发是否应该使用动态内存分配

    我遇到的许多嵌入式软件开发人员提出的一个我觉得特别有趣的话题是动态内存分配——在需要时获取内存块。这种看似简单和常规的操作会带来大量问题。这些并不局限于嵌入式开发——许多桌面应用程序都会出现
    的头像 发表于 07-15 14:16 1286次阅读
    嵌入式开发是否应该使用<b class='flag-5'>动态内存</b><b class='flag-5'>分配</b>

    类和动态内存分配(二)

    若要将单个值转换为类类型,则需要创建对应的类构造函数
    的头像 发表于 07-18 10:47 239次阅读

    你知道吗? 51单片机也有动态内存分配

    一、简述其实在51单片机中也可以使用动态内存动态内存其实就是划出一块内存区域,将这块内存进行管理,称为内存管理。51单片机可以使用c语言自
    的头像 发表于 04-26 08:10 44次阅读
    你知道吗? 51单片机也有<b class='flag-5'>动态内存</b><b class='flag-5'>分配</b>