C++中的简单内存管理---初步认识

OC里面给变量赋值有2种方法第一种是直接用下划线的,也就是实例变量:_button=       第二种是使用属性:self.button
= ....这两种有何区别???

以下项目是创建了一个C++项目   简单模拟创建对象和给变量赋值的情况

首先创建了一个NSObject类,在OC里面继承NSObject类的都有retain  release  autorelease。。。。等方法来管理内存的

NSObject的头文件,声明方法

//
//  NSObject.h
//  autorelease
//
//  Created by 06 on 15/1/24.
//  Copyright (c) 2015年 黄永锐. All rights reserved.
//

#ifndef __autorelease__NSObject__
#define __autorelease__NSObject__

#include <iostream>

class NSObject{
    int m_retainCount;//计数器
    //这里面应该还有一个自动释放池的对象

public:
    //加1
    void retain();
    //减1
    void release();
    //自动释放
    void autorelease();

    //计数器的getter方法
    int retainCount();
};

#endif /* defined(__autorelease__NSObject__) */

NSObject的实现文件.cpp  里面实现了头文件里面声明的方法

//
//  NSObject.cpp
//  autorelease
//
//  Created by 06 on 15/1/24.
//  Copyright (c) 2015年 黄永锐. All rights reserved.
//

#include "NSObject.h"
using namespace std;

//加1
void NSObject:: retain(){
    m_retainCount++;
}
//减1
void NSObject:: release(){
    //如果当前对象不为空  并且引用计数器大于0
    if (this !=nullptr && m_retainCount > 0) {
        m_retainCount--;
    }

}
//自动释放
void NSObject:: autorelease(){
    //把当前对象添加到自动释放池当中  延迟release
    //当自动释放池对象释放的时候,会把里面保存的对象全部release一次
    //这里只是简单模拟,没有延迟释放
    m_retainCount--;
}

//计数器的getter方法
int NSObject:: retainCount(){
    return m_retainCount;
}

接着创建UIButton类继承于NSObject类

头文件

//
//  UIButton.h
//  autorelease
//
//  Created by 06 on 15/1/24.
//  Copyright (c) 2015年 黄永锐. All rights reserved.
//

#ifndef __autorelease__UIButton__
#define __autorelease__UIButton__

#include <iostream>
#include "NSObject.h"

class UIButton:public NSObject{
public:
    //创建对象
    static UIButton* button();
    //初始化方法
    void init();

};

#endif /* defined(__autorelease__UIButton__) */

UIButton类的实现文件.cpp

//
//  UIButton.cpp
//  autorelease
//
//  Created by 06 on 15/1/24.
//  Copyright (c) 2015年 黄永锐. All rights reserved.
//

#include "UIButton.h"
using namespace std;

//创建对象
UIButton* UIButton:: button(){
    //开辟内存空间
    UIButton* btn = new UIButton;//OC的这一步是alloc会导致引用计数器加1,而C++这一步没办法加1
    btn->retain();
    btn->init();

    //实际上这三步就相当于OC里面的[[..alloc]init]
    //现在是btn指针加1  注意 内存管理  谁加谁减。如果在这里直接release那么返回的可能就没有了,如果不release的话,btn这个指针在栈里出了这个方法就会弹栈了  就找不到btn了.....所以把它放在自动释放池里面,这样出了这个方法还能用,也不用考虑内存管理的问题

    btn->autorelease();

    return btn;
}
//初始化方法
void  UIButton:: init(){

}

//OC里面给变量赋值有2种方法 第一:_button   第二:self.button
// 创建对象  这里UIButton* button相当于_button = ...
//  UIButton* button = UIButton::button();//现在button引用计数器为1  因为autorelease还没有执行  如果不考虑延迟释放的问题,其实质上为0了。因为UIButton::button()里面加1 也减1了
//也就是说button的计数器为0  在这个方法里面可以用,出了这个方法就访问不到button了

最后创建一个MyClass类  也是继承NSObject

头文件

//
//  MyClass.h
//  autorelease
//
//  Created by 06 on 15/1/24.
//  Copyright (c) 2015年 黄永锐. All rights reserved.
//

#ifndef __autorelease__MyClass__
#define __autorelease__MyClass__

#include <iostream>
#include "UIButton.h"

//在OC里面声明一个属性,编译器会帮你做几件事呢??会生成一个保护的(实例)变量,还会生成2个公开的方法setter  getter

class MyClass : public NSObject{
public://公有的
    void setButton(UIButton* button);
    UIButton* getButton();

    //
    void setButton2(UIButton* button);
    UIButton* getButton2();

    //初始化方法
    void init();//初始化方法里把保护的_button指针创建出来让它指向一个对象
protected://保护的
    UIButton* _button;
    UIButton* _button2;

private://私有的
};

#endif /* defined(__autorelease__MyClass__) */

MyClass类的实现文件.cpp

//
//  MyClass.cpp
//  autorelease
//
//  Created by 06 on 15/1/24.
//  Copyright (c) 2015年 黄永锐. All rights reserved.
//

#include "MyClass.h"
using namespace std;

void MyClass:: init(){
    //在OC里面可以直接使用下划线创建对象
    _button = UIButton::button();//这种创建的对象出来引用计数器为0
    cout << "使用下划线创建对象的计数器为: " << _button->retainCount() << endl;

    //在OC里面还可以这样  self.相当于调用了button的setter方法
    //self.button = UIButton::button();//这样的计数器为1
    //在C++里面应该怎样呢?
    this->setButton(UIButton::button());
    cout << "使用setter方法创建对象的计数器为: " << _button->retainCount() << endl;

    this->setButton2(UIButton::button());//相当于self.button2 = ....//现在button2的引用计数器应该也为1
    cout << "button2 count: " << _button2->retainCount() << endl;

    UIButton *but = _button;//指向_button
    cout << "=== 赋值之前button1 button2的引用计数器都为1 ===" << endl;
    //调用button1的方法
    this->setButton(_button2); //相当于self.button = _button2;
#pragma 注意执行完这句之后_button也是指向了_button2对象了

    cout << "button1 count: " << _button->retainCount() << endl;//实际上是调用button2的retainCount
    cout << "button2 count: " << _button2->retainCount() << endl;
    cout << "_button原来指向的那个对象的引用计数器为: " << but->retainCount() << endl;  //出了方法就会被销毁

#pragma _button2要怎么释放?  现在_button 和_button2  都在用它
    //谁不用 谁减
    _button->release();
    cout << _button->retainCount() << endl;

    _button2->release();
    cout << _button2->retainCount() << endl;//到这里_button2的引用计数器为0了出了方法就会被销毁
}

#pragma mark - button 的setter getter方法
void MyClass:: setButton(UIButton* button){
    //1.判断是否自己负值
    if (_button == button) {
        return;//如果是自己给自己赋值  那就不用操作
    }else{
    //如果不是
        //2.先释放原有内存空间   在OC里面对已经是0的计数器再release也没关系
        _button->release();  //A-1

        //3.赋值操作
        _button = button;    //A = B
        //4.retain
        _button->retain();   //B++
    }
}

UIButton* MyClass:: getButton(){
    return _button;
}

#pragma mark - button2的setter getter方法

void MyClass:: setButton2(UIButton* button){
    if (_button2 == button) {
        return;
    }else{
        //2.先释放原有内存空间   在OC里面对已经是0的计数器再release也没关系
        _button2->release();
        //3.赋值操作
        _button2 = button;
        //4.retain
        _button2->retain();
    }
}

UIButton* MyClass:: getButton2(){
    return _button2;
}

在主函数里面创建MyClass对象

//
//  main.cpp
//  autorelease
//
//  Created by 06 on 15/1/24.
//  Copyright (c) 2015年 黄永锐. All rights reserved.
//

#include <iostream>
#include "MyClass.h"
using namespace std;

int main(int argc, const char * argv[])
{
    MyClass* myclass = new MyClass;
    myclass->init();

    //从输出结果可以看出,使用下划线创建对象的引用计数器为0.  使用setter方法创建的对象引用计数器为1
    return 0;
}

运行结果如下:

使用下划线创建对象的计数器为: 0
使用setter方法创建对象的计数器为: 1
button2 count: 1
=== 赋值之前button1 button2的引用计数器都为1 ===
button1 count: 2
button2 count: 2
_button原来指向的那个对象的引用计数器为: 0
1
0
Program ended with exit code: 0

/////////////////////////////// ======= 额外 ========  ////////////////////////////////////

数组里面也会给元素加 1

数组里面为什么只能放对象??就是因为加 1

数组addObject一个元素进数组的时候,数组会负责给传进来的元素加1。

为什么数组要加1??谁用谁加。把元素放进数组里,也就是数组要用。

怎么加?

会调用你传进来的那个元素的retain方法,但是你的这个对象没有继承NSObject,不存在retain方法,就会出现问题了。例如传进一个int
100;  100根本就没有retain方法。 所以要把int封装成NSNumber类型,因为NSNumber继承NSObject

数组addObject的时候会加1 ,
那么什么时候会减1??

它用它加,不用了remove的时候会减1.

另外一种情况:不断的往数组里面添加元素,现在数组要销毁了,在销毁之前并没有全部remove

会不会有内存泄漏??

也不会,因为数组先把它里面所有的元素都release一次,自己才销毁.

时间: 2024-12-29 11:54:29

C++中的简单内存管理---初步认识的相关文章

c++中的动态内存管理

c++中的动态内存管理问题 c++中使用new和delete实现动态内存管理.new和delete实现动态管理对象,new[]和delete[]实现动态管理对象数组.c++中的new和delete运算符均使用我们c中学过的malloc和delete函数实现动态内存的开辟. 首先,先简单介绍下c中的几个动态内存函数malloc,realloc,calloc,free; void *malloc(size_t size); //动态内存开辟函数 void free(void *pointer);  

39-oc集合中对象的内存管理

集合中对象的内存管理 集合的内存管理原则是什么 当把一个对象添加到集合中时,这个对象会做了一次retain操作,计数器会+1 当一个集合被销毁时,会对集合里面的所有对象做一次release操作,计数器会-1 当一个对象从集合中移除时,会对这个对象做一次release操作,计数器会-1 集合方法的普遍规律是什么 如果方法名是add\insert开头,那么被添加的对象,计数器会+1 如果方法名是remove\delete开头,那么被移除的对象,计数器-1

(译) Google Flutter 中的简单状态管理

原文链接 我是如何遇见 Google Flutter的 这对我来这是像往常一样的码代码的一天.我的一个朋友在我们的开发者群组中发了这么一个问题,是否有人尝试过Google Flutter.它想要知道React Native 和 Google Flutter之间的比较.这个问题让我种草了Google Flutter.我之前从没有听过Google Flutter.它是否值得与React Native进行比较,就像AngularJS相较于ReactJS? 我必须承认.我是一个React的迷弟.我已经使

NETTY4中的BYTEBUF 内存管理

转 http://iteches.com/archives/65193 Netty4带来一个与众不同的特点是其ByteBuf的重现实现,老实说,java.nio.ByteBuf是我用得很不爽的一个API,相比之下,通过维护两个独立的读写指针,io.netty.buffer.ByteBuf要简单不少,也会更高效一些.不过,Netty的ByteBuf带给我们的最大不同,就是他不再基于传统JVM的GC模式,相反,它采用了类似于C++中的malloc/free的机制,需要开发人员来手动管理回收与释放.从

iOS开发中的ARC内存管理de技术要点

本文旨在通过简明扼要的方式总结出iOS开发中ARC(Automatic Reference Counting,自动引用计数)内存管理技术的要点,所以不会涉及全部细节.这篇文章不是一篇标准的ARC使用教程,并假定读者已经对ARC有了一定了解和使用经验.详细的关于ARC的信息请参见苹果的官方文档与网上的其他教程:) 本文的主要内容: ARC的本质 ARC的开启与关闭 ARC的修饰符 ARC与Block ARC与Toll-Free Bridging ARC的本质 ARC是编译器(时)特性,而不是运行时

iOS中引用计数内存管理机制分析

在 iOS 中引用计数是内存的管理方式,尽管在 iOS5 版本号中.已经支持了自己主动引用计数管理模式.但理解它的执行方式有助于我们了解程序的执行原理.有助于 debug 程序. 操作系统的内存管理分成堆和栈. 在堆中分配的内存,都试用引用计数模式:在栈中则不是. NSString 定义的对象是保存在栈中,所以它没有引用计算.看一些书上说它的引用计算会是 fffffffff 最大整数.測试的结果显示它是- 1. 对该对象进行 retain 操作.不好改变它的 retainCount 值. Mut

iOS中引用计数内存管理机制分析总结(NSString引用计数为-1的情况)

在 iOS 中引用计数是内存的管理方式,虽然在 iOS5 版本中,已经支持了自动引用计数管理模式,但理解它的运行方式有助于我们了解程序的运行原理,有助于 debug 程序.   操作系统的内存管理分成堆和栈. 在堆中分配的内存,都适用引用计数模式:在栈中则不是. NSString 定义的对象是保存在栈中,所以它没有引用计数,不是通过引用计数对内存进行管理的.之前我在一篇博客上看,说常量的引用计数会是一个很大的整数,测试的结果显示它是-1. 对该对象进行 retain 操作,不好改变它的 reta

C 内存管理初步了解

1 首先变量了解几个概念 静态变量:用 static 修饰的变量 局部变量: 存储在栈区:作用域是函数块内:生存期是直到函数块结束 全局变量:存储在静态区:作用域是从定义到本源程序结束,生存期是运行期间 静态全局变量:存储在静态区:作用域是函数块内:生存期是运行期间 静态局部变量:存储在静态区:作用域是从定义到工程源程序结束:生存期是运行期间 2 内存的分区:一般为5大分区,栈区,堆区,静态区,常量区,代码区(内存地址从高到底) 栈区: *函数参数以及局部变量存储的区域 *栈区的存储空间由高向低

C++中的自定义内存管理

1,问题: 1,new 关键字创建出来的对象位于什么地方? 1,位于堆空间: 2,有没有可能位于其它地方? 1,有: 2,通过一些方式可以使动态创建的对象位于静态存储区: 3,这个存储区在程序结束后释放: 2,new/delete 被忽略的事实: 1,new/delete 的本质是 C++ 预定义的操作符: 1,new/delete 是关键字,但本质是预定义的操作符: 2,C++ 中操作符可以重载: 2,C++ 对这两个操作符做了严格的行为定义: 1,new: 1,获取足够大的内存空间(默认为堆