C++继承体系设计陷阱预警,虚函数与纯虚函数混用导致的内存泄漏风险(真实案例剖析)

第一章:C++ 虚函数与纯虚函数区别

在C++的面向对象编程中,虚函数和纯虚函数是实现多态的关键机制。它们允许基类定义接口,并由派生类提供具体实现,但二者在语法和语义上存在显著差异。

虚函数的基本概念

虚函数是在基类中使用 virtual 关键字声明的成员函数,它允许在派生类中被重写。当通过基类指针或引用调用该函数时,会根据实际对象类型动态绑定到对应的实现。

class Base {
public:
    virtual void show() {
        std::cout << "Base class show" << std::endl;
    }
};

class Derived : public Base {
public:
    void show() override {
        std::cout << "Derived class show" << std::endl;
    }
};
上述代码中,show() 是虚函数,调用时将根据对象实际类型决定执行哪个版本。

纯虚函数与抽象类

纯虚函数是一种特殊的虚函数,其声明以 = 0 结尾,不提供实现。包含纯虚函数的类称为抽象类,不能实例化。

class Shape {
public:
    virtual void draw() = 0; // 纯虚函数
};

class Circle : public Shape {
public:
    void draw() override {
        std::cout << "Drawing a circle" << std::endl;
    }
};
在此例中,Shape 是抽象类,必须由子类实现 draw() 才能创建实例。

主要区别对比

  • 虚函数可有默认实现,纯虚函数必须由派生类实现
  • 含有纯虚函数的类为抽象类,无法直接实例化
  • 纯虚函数用于定义接口规范,强调“必须实现”
特性虚函数纯虚函数
关键字virtualvirtual ... = 0
可否实例化类可以不可以(抽象类)
是否必须重写否是

第二章:虚函数机制深度解析

2.1 虚函数的语法定义与运行时多态实现原理

在C++中,虚函数通过在成员函数声明前添加`virtual`关键字实现动态绑定。当基类指针或引用调用虚函数时,实际执行的是派生类中重写的版本,从而实现运行时多态。
虚函数的基本语法
class Base {
public:
    virtual void show() {
        std::cout << "Base class show" << std::endl;
    }
};

class Derived : public Base {
public:
    void show() override {
        std::cout << "Derived class show" << std::endl;
    }
};
上述代码中,virtual关键字使show()成为虚函数,override确保派生类函数正确重写基类虚函数。
运行时多态的实现机制
虚函数依赖虚函数表(vtable)和虚指针(vptr)实现动态分发。每个含有虚函数的类都有一个vtable,存储指向各虚函数的指针;每个对象包含一个vptr,指向其类的vtable。
对象内存布局内容
vptr指向虚函数表
成员变量实例数据

2.2 虚函数表(vtable)与虚函数指针(vptr)底层剖析

在C++多态实现中,虚函数表(vtable)和虚函数指针(vptr)是核心机制。每个含有虚函数的类在编译时生成一张虚函数表,存储指向各虚函数的函数指针。
虚函数指针的布局
对象实例化时,编译器自动在对象头部插入vptr,指向所属类的vtable。该指针由构造函数初始化,析构函数销毁。
class Base {
public:
    virtual void func() { cout << "Base::func" << endl; }
};
// 编译后等价于:对象内存 = vptr + 成员变量
上述代码中,vptr 指向包含 func() 地址的vtable,调用时通过 vptr->vtable[0]() 动态分发。
多态调用的执行流程
  • 通过基类指针调用虚函数
  • 访问对象的vptr
  • 查表获取实际函数地址
  • 执行对应函数

2.3 继承体系中虚函数重写的正确姿势与常见误区

在C++继承体系中,虚函数的正确重写是实现多态的关键。重写要求基类函数声明为virtual,派生类函数与基类的函数签名完全一致。
虚函数重写的语法规范
class Base {
public:
    virtual void show() { 
        std::cout << "Base show\n"; 
    }
};

class Derived : public Base {
public:
    void show() override {  // 使用override确保重写正确
        std::cout << "Derived show\n";
    }
};
上述代码中,override关键字显式表明意图重写,若签名不匹配将引发编译错误。
常见误区
  • 返回类型不一致导致隐藏而非重写
  • 参数列表细微差异(如const、引用)造成函数隐藏
  • 遗漏virtual或override,失去多态行为
正确使用override可有效避免这些陷阱。

2.4 析构函数声明为虚函数的必要性及性能权衡

在C++多态体系中,基类析构函数是否声明为虚函数直接影响对象资源释放的正确性。若通过基类指针删除派生类对象,而析构函数非虚,则仅调用基类析构,造成资源泄漏。
虚析构函数的必要性
当类设计用于继承时,析构函数应声明为虚函数,确保派生类析构时能正确触发完整析构链。
class Base {
public:
    virtual ~Base() { // 虚析构确保正确调用派生类析构
        std::cout << "Base destroyed";
    }
};

class Derived : public Base {
public:
    ~Derived() override {
        std::cout << "Derived destroyed";
    }
};
上述代码中,若 ~Base() 非虚,删除 Derived 实例时将仅执行基类析构。
性能与设计权衡
虚函数引入虚表指针,轻微增加内存开销,并使析构调用间接化,带来运行时成本。对于不用于继承的类,不应盲目声明虚析构。

2.5 实践案例:非虚析构导致的对象销毁不完整问题

在C++多态编程中,若基类的析构函数未声明为虚函数,通过基类指针删除派生类对象时,将仅调用基类析构函数,导致派生类部分资源未被释放。
典型问题代码示例

class Base {
public:
    ~Base() { std::cout << "Base destroyed"; }
};

class Derived : public Base {
public:
    ~Derived() { std::cout << "Derived destroyed"; }
    int* data = new int[100];
};
上述代码中,Base 的析构函数非虚。当执行 delete basePtr;(指向 Derived 对象)时,Derived 的析构函数不会被调用,造成内存泄漏。
正确做法
应将基类析构函数声明为虚函数:

virtual ~Base() { std::cout << "Base destroyed"; }
此时,删除派生类对象会先调用 Derived 析构,再调用 Base 析构,确保完整清理资源。

第三章:纯虚函数与抽象类设计精髓

3.1 纯虚函数的定义方式及其对类抽象性的提升

在C++中,纯虚函数通过在函数声明后添加 = 0 来定义,使类成为抽象类,无法实例化。这种方式强制派生类重写该函数,从而实现接口与实现的分离。
纯虚函数的语法结构
class Shape {
public:
    virtual void draw() = 0; // 纯虚函数
};
上述代码中,draw() 是纯虚函数,Shape 成为抽象类。任何继承 Shape 的子类必须实现 draw(),否则仍为抽象类。
提升类的抽象性
  • 统一接口:所有派生类遵循相同的函数签名;
  • 多态支持:可通过基类指针调用实际类型的实现;
  • 设计契约:明确子类必须提供的功能。
这一机制广泛应用于图形渲染、插件架构等需要高度扩展的系统中。

3.2 抽象类作为接口规范在大型项目中的应用模式

在大型项目中,抽象类常被用作定义统一的接口规范,确保子类遵循特定的方法签名与行为契约。
核心设计动机
通过抽象类可预定义公共逻辑骨架,同时强制子类实现关键业务方法,提升代码一致性与可维护性。
典型应用场景
例如,在支付系统中定义统一处理流程:

public abstract class PaymentProcessor {
    // 模板方法
    public final void processPayment(double amount) {
        validate(amount);
        double fee = calculateFee(amount); // 共享逻辑
        executePayment(amount + fee);     // 子类实现
    }

    protected abstract void executePayment(double total);

    private void validate(double amount) {
        if (amount <= 0) throw new IllegalArgumentException();
    }

    protected double calculateFee(double amount) {
        return amount * 0.02; // 默认手续费
    }
}
上述代码中,processPayment为模板方法,封装固定流程;executePayment由子类实现,支持差异化支付渠道(如微信、支付宝);calculateFee提供默认实现,允许选择性重写。
优势对比
特性抽象类纯接口
共享代码支持不支持(Java 8+ default 方法除外)
方法强制实现支持支持

3.3 实践案例:通过纯虚函数构建可扩展的插件架构

在大型系统设计中,插件化架构能显著提升系统的可维护性与扩展性。C++中的纯虚函数为实现多态接口提供了语言层面的支持,是构建插件体系的核心机制。
定义统一插件接口
通过抽象基类声明纯虚函数,规范插件行为:
class Plugin {
public:
    virtual void initialize() = 0;
    virtual void execute() = 0;
    virtual ~Plugin() = default;
};
上述代码定义了插件必须实现的初始化与执行逻辑,= 0 表示纯虚函数,子类需重写以完成具体功能。
插件注册与加载机制
使用工厂模式结合动态库(如 .so 或 .dll)实现运行时加载:
  • 每个插件共享同一接口头文件
  • 主程序通过 dlopen/dlsym 加载符号并实例化对象
  • 利用虚函数表调用具体实现,实现解耦

第四章:混用虚函数与纯虚函数的风险场景

4.1 错误继承链设计引发的资源管理漏洞分析

在面向对象设计中,不当的继承链可能导致资源管理责任模糊,进而引发内存泄漏或双重释放等安全问题。
典型错误模式
当基类未声明虚析构函数,而派生类持有动态分配资源时,通过基类指针删除对象将无法正确调用派生类析构函数。

class ResourceHolder {
public:
    ~ResourceHolder() { delete ptr; } // 非虚析构函数
private:
    int* ptr = new int(42);
};

class Derived : public ResourceHolder {
    // 派生类扩展资源管理逻辑
};
上述代码中,若以 ResourceHolder* 删除 Derived 实例,派生部分资源将不会被清理。
修复策略对比
  • 基类析构函数应声明为 virtual
  • 使用智能指针管理生命周期
  • 避免深层继承用于资源聚合

4.2 构造与析构顺序中虚函数调用的未定义行为陷阱

在C++对象的构造和析构过程中,虚函数表尚未完全建立或已被销毁,此时调用虚函数将导致未定义行为。
构造期间的虚函数调用风险
当基类构造函数调用虚函数时,实际执行的是当前构造层级的版本,而非派生类重写版本。

class Base {
public:
    Base() { speak(); }  // 危险:调用Base::speak()
    virtual void speak() { std::cout << "Base\n"; }
};

class Derived : public Base {
public:
    void speak() override { std::cout << "Derived\n"; }
};
上述代码中,Base 构造函数调用 speak() 时,Derived 部分尚未构造,因此只会调用 Base::speak(),无法实现多态。
析构期间的行为一致性
同样,在析构函数中调用虚函数也会绑定到当前层级的实现,因为派生类部分已销毁。
  • 构造时:从基类到派生类,虚表逐层构建
  • 析构时:从派生类到基类,虚表逐层销毁
  • 建议:避免在构造/析构函数中调用虚函数

4.3 实践案例:因纯虚函数未完全实现导致的运行时崩溃

在C++多态设计中,若派生类未完全实现基类的纯虚函数,将导致链接错误或运行时崩溃。此类问题常出现在大型继承体系中,尤其当接口扩展后未同步更新所有子类。
问题复现代码

class Shape {
public:
    virtual void draw() = 0;  // 纯虚函数
    virtual void resize() = 0;
};

class Circle : public Shape {
public:
    void draw() override { /* 正确实现 */ }
    // resize 未实现
};
上述代码在编译阶段不会报错,但在实例化 Circle 时,由于 resize() 未被实现,链接器无法生成完整虚表,引发链接错误。
解决方案与最佳实践
  • 使用 override 关键字显式声明重写,提升可读性;
  • 在CI流程中启用 -Werror=non-virtual-dtor 和 -Werror=overloaded-virtual 编译警告;
  • 优先通过静态分析工具(如Clang-Tidy)检测未实现的纯虚函数。

4.4 防御式编程策略:避免内存泄漏的RAII与智能指针整合方案

在C++中,RAII(Resource Acquisition Is Initialization)是防御式编程的核心机制,确保资源在对象构造时获取、析构时释放。结合智能指针可有效规避手动内存管理带来的泄漏风险。
智能指针类型对比
类型所有权模型适用场景
std::unique_ptr独占单一所有者生命周期管理
std::shared_ptr共享多所有者共享资源
std::weak_ptr观察者打破循环引用
RAII与智能指针协同示例

class ResourceManager {
    std::unique_ptr<int[]> data;
public:
    ResourceManager(size_t size) : data(std::make_unique<int[]>(size)) {}
    // 析构函数自动释放内存
};
上述代码中,std::make_unique 在构造时分配内存,对象销毁时自动调用析构函数释放资源,无需显式 delete。该模式将资源生命周期绑定至对象生命周期,从根本上防止内存泄漏。

第五章:总结与最佳实践建议

性能监控与调优策略
在生产环境中,持续监控系统性能是保障服务稳定的关键。推荐使用 Prometheus + Grafana 构建可视化监控体系,定期采集应用延迟、CPU 使用率和内存消耗等核心指标。
  • 设置告警规则,当请求延迟超过 200ms 持续 5 分钟时触发通知
  • 定期分析 GC 日志,优化 JVM 参数以减少停顿时间
  • 使用 pprof 对 Go 服务进行 CPU 和内存剖析
代码层面的最佳实践
以下是一个 Go 语言中避免 context 泄露的正确用法示例:
// 启动带超时控制的后台任务
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel() // 确保释放资源

result, err := longRunningOperation(ctx)
if err != nil {
    log.Printf("操作失败: %v", err)
    return
}
部署与配置管理
采用基础设施即代码(IaC)原则管理环境一致性。下表列出不同环境的资源配置建议:
环境CPU 核心数内存副本数
开发24GB1
生产816GB3
安全加固措施

实施最小权限原则:

  1. 数据库连接使用只读账号访问非敏感数据
  2. Kubernetes Pod 配置非 root 用户运行
  3. API 网关层启用速率限制(如 1000 请求/分钟/IP)
【学习系列】SAP RAP 17:RAP应用部署集成至Fiori Launchpad 【S4HC Public Edition】 本文详细介绍了在SAP S/4HANA Cloud环境中部署RAP应用集成到Fiori Launchpad的两种方法:使用BAS(SAP Business Application Studio)和VSCode。主要步骤包括:1)在BTP中配置Destination连接ES环境;2)设置信任关系;3)创建BAS开发空间;4)通过Fiori应用生成器部署RAP应用;5)创建IAM App、Business Catalog和Business Role;6)配置Launchpad Space和Pages。文章还提供 阅读详情

相关推荐

Lakes.AERMOD.View.v8.9.0 1CD大气扩散模型软件包

Lakes.AERMOD.View.v8.9.0 1CD大气扩散模型软件包 Lakes Environmental ARTM View v1.4.2 1CD放射物扩散模拟模型 Aermod View是一套完整的、功能强大的大气扩散模型软件包,并将美国EPA指定的大气扩散模型(如下)完美的集成成为一个综合的操作平 台: - AERMOD 电话TEL:18980583122  客服 QQ:11

yyii0000的博客 4001

delete-non-virtual-dtor 问题解决办法

编译过程中出现如下警告:  warning: deleting object of abstract class type ‘CAN_driver’ which has non-virtual destructor will cause undefined behaviour [-Wdelete-non-virtual-dtor]      delete veh_CAN; 其中代码结构大致如下...

qcxyliyong的博客 5766

PyTorch实战:手把手教你用QAT量化感知训练拯救模型精度(附避坑指南)

本文详细介绍了如何使用PyTorch进行QAT量化感知训练,以提升模型在边缘设备上的推理精度。通过核心原理讲解、实战代码示例和避坑指南,帮助开发者掌握从环境配置、模型训练到边缘部署的全流程,有效解决传统量化方法导致的精度损失问题。

c7d8e的博客 329

[C++]虚析构函数

虚函数对应一个虚表vtable,这个vtable存储在对象的内存空间中,虚函数被通过查询虚表vtable调用,所以一定要通过构造函数实例化内存空间,才会有虚表,所以构造函数不可能为虚函数。,此时就用到了虚析构函数,与普通虚函数不同,它并非直接查找子类中的函数覆盖自身,而是同时调用自身析构函数与子类构造函数,这样就解决了利用多态时可能造成内存泄漏的问题。虚函数(virtual)用在类中的普通方法中的时候,会根据虚表(vtable)查找派生类中对于当前函数名的用法,虚函数可以用于实现多态,而。

SlanderMC的博客 458

数字IC后端PPA优化实战:Innovus中Timing一致性策略与Module Region布局技巧

本文深入探讨了数字IC后端设计中PPA优化的核心挑战,重点解析了Innovus与PrimeTime之间Timing不一致的根本原因。通过实战案例,详细介绍了在Innovus中设置Timing Margin、Derate以及RC Scale Factor等关键策略,以校准时序视图。同时,文章分享了利用Module Region进行物理布局规划的技巧,将关键模块约束在最优区域,并结合Group Path等进阶方法,有效提升时序收敛效率与PPA结果的可预测性。

f9g0h的博客 2687

【24届秋招总结】24届数字IC秋招给学弟学妹们的99条建议(标题党)

针对2023年找实习、秋招、谈薪资等方面的个人经验进行总结,希望对后续同学们找工作有所帮助

qq_42135020的博客 4462

【GCC】编译选项与告警(C/C++建议开启)

当使用 -Werror 时,所有警告都会被提升为错误,导致编译失败。当浮点数(如 float 或 double)被隐式转换为整数类型(如 int)时,小数部分会被直接截断,导致精度丢失。gcc开启优化有时候报错会更多,建议编译时开启优化,没有优化,下面不报错,开启优化,func就内联了会报错,变量没有初始化。-Wfloat-conversion 是 GCC 编译器中的一个警告选项,用于检测浮点数与整数之间的隐式转换问题。当整数类型被隐式转换为浮点数类型时,如果浮点数无法精确表示该整数值,则会引发精度损失。

喜欢打篮球的普通人 993

使用 Python 爬取 Wikipedia 数据:抓取百科条目及其内容

维基百科的 API 提供了一些方便的接口,通过这些接口,我们可以轻松获取到维基百科的条目、类别、图片和其他相关信息。维基百科的 API 主要是基于 HTTP 请求的,通过向特定的 URL 发送 GET 请求来获取信息。:获取指定条目的内容。在本博客中,我们介绍了如何使用 Python 爬取维基百科的条目数据。通过使用 Wikipedia API 和网页抓取技术,我们能够高效地获取条目内容,并将其存储和分析。希望本篇教程能帮助你深入理解如何抓取和处理维基百科的数据。

2201_76125261的博客 475

C/C++内存泄漏分析和解决方法

本文详细介绍了C/C++编程中的内存泄漏问题以及预防、解决办法。

贫道绝缘子的博客 4222

第四节:Vben Admin登录对接后端getUserInfo接口

上一节,我们完成了/api/auth/login接口的创建,通过login接口,我们完成了登录和Token的生成。但是登陆还是报404返回,发现是Vben Admin又请求了一个/api/getUserInfo接口,本节我们就来分析完成这个接口本节,我们完成了getUserInfo接口,完成了登录操作,成功的进入到工作台页面。

cuiwin的专栏 2846

SolidWorks速成教程P1——简介及基础操作

SolidWorks教程P1——简介及基础操作

嵌入式阿齐Archie 2万+

C++析构函数Segfault深度解析:六大成因与实战解决方案

在C++编程中,内存管理是核心挑战之一,其核心机制RAII(资源获取即初始化)通过构造函数和析构函数自动管理资源生命周期。然而,当程序在对象销毁阶段访问无效内存时,便会引发Segmentation Fault(段错误),这类错误在析构函数中尤为隐蔽和棘手。其原理通常涉及对象生命周期的错乱、资源所有权的混淆或多线程环境下的数据竞争。从技术价值看,深入理解析构函数中的崩溃成因,是提升代码健壮性、掌握现代C++资源管理范式的关键。常见应用场景包括复杂资源管理类、多线程服务端程序以及高频使用的库开发。本文聚焦于双重

weixin_34082789的博客 347

什么是垂直同步?电脑快速消除屏幕撕裂与提升游戏性能的方法 垂直同步、游戏画面撕裂、游戏优化、VSync、FPS、FreeSync、G-Sync、显卡驱动更新、游戏画质、输入延迟

看这张动图,左边的画面出现了明显“切开”的断层现象,而右边画面非常流畅,没有撕裂。这正是「垂直同步」开关的区别。:每秒生成多少帧图像。比如 60FPS 表示一秒钟显示 60 张图片。刷新率(Refresh Rate):显示器每秒刷新几次画面,单位是赫兹(Hz)。60Hz 表示每秒刷新 60 次。参数说明FPS显卡渲染速度(逻辑帧率)刷新率显示器的显示频率(物理限制)当 FPS 高于刷新率时,显卡渲染的画面来不及被显示器显示,导致撕裂。屏幕撕裂(Screen Tearing)

代码简单说 Vue、JAVA、PHP、Node.js 熟练运用,接口、架构、性能全搞定。 1347

内存泄露之-虚析构函数

#include&lt;iostream&gt; class Father { public: Father() { printf("Father\n"); } ~Father() //这样会导致内存泄漏,解决方法:virtual ~Father(){...} { printf("~Father\n"); } public: virtual voi...

bocai1215的博客 340

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

虚拟机交叉编译openCV详细步骤及bug解决详解

目的:交叉编译openCV库,用于xilinx的MIZ7020的FPGA的片上ARM运行。 目录 一、安装依赖项 二、安装编译器 2.1 编译器安装与路径 2.2 环境变量配置 三、安装依赖库 3.1 下载依赖库 3.2 交叉编译依赖库 zlib的交叉编译为例: 流程 libjpeg的交叉编译 libpng的交叉编译 yasm的交叉编译 libx264的交叉编译 li...

祥瑞的技术博客 5727

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

虚析构函数的内存泄露问题谈。

(1)如果一个类不做父类,是不应该给该类增加一个虚析构函数的。 (2)不要随便public一个自己不熟悉的类,有时候有一个第三方的类,如果他的析构函数不是虚函数, 而我们进行了public继承时,就有可能会发生内存泄露的问题。 (3)如果子类public继承父类,那么父类指针可以指向子类对象。 (4)如果子类private或者protected继承父类,那么父类指针不可以指向子类对象。 (5)如果让父类指针指向子类对象,那么就需要用public继承,这个时候父类就需要提供虚析构函数。 总结应该使用虚析构函数

qq_38158479的博客 314

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

消除警告

#pragmaclang diagnostic push#pragmaclang diagnostic ignored"-Wdeprecated-declarations"这里写出现警告的代码#pragmaclang diagnostic pop源网址WarningMessage-WCFString-literalinput conversion stopped due to an input b

sinat_32972877的博客 1万+

Android编译源码时禁用werror避免报错

修改源码目录下的 build/core/config.mk 如下: - TARGET_ERROR_FLAGS := -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point + #TARGET_ERROR_FLAGS := -Werror=return-type -Wer

WJ S的专栏 1万+

为什么要将一个父类的析构函数写成一个虚函数,和内存泄漏有关,怎么理解?

<br />今天被一个问题困扰了一下,当我们定义了一个类,然后在让一个子类去继承这个类,定义子类和父类都写好构造函数和析构函数,实例化这个子类对象时,会先调用父类的构造函数,在调用子类的构造函数,释放这个对象的时候恰恰相反 ,先调用子类析构函数,在调用父类析构函数,那么,问题就是存在这种继承机制的类是否会额外消耗很多的存储空间呢?比如说一个类,继承多个父类或者说链式继承,即他的父类还继承了别的类,那么示例化一个子类对象难道说要将他的所有父类都实例化?期待高手回答这个问题,相信还有很多人对这个不是很理解,固然

知道者 7647

虚析构函数(解决内存泄漏)(13)

#ifndef A_H #define A_H #include <iostream> using namespace std; class A{ public: A(); virtual ~A(); }; #endif #include "A.h" A::A(){ cout << "A::A()" << endl; } A::~A(){ cout...

xt18971492243的博客 196

QT之全局忽略编译警告QMAKE_CXXFLAGS

全局忽略编译警告QMAKE_CXXFLAGS

星辰大海 1万+

gcc编译部分编译选项

我只写出一些我没有在文档中查到的,网上也搜索不出来什么明确的资料。正确性实在不敢保证。 https://gcc.gnu.org/onlinedocs/gcc-7.3.0/gcc/Option-Summary.html#Option-Summary 这是文档。 使用gcc命令显示的帮助信息 用法:gcc [选项] 文件... 选项: -pass-exit-codes

JabamiYu的博客 3万+

C++继承中的虚析构函数

看看下面程序有什么错误: #include &lt;iostream&gt;using namespace std;class Father{public: Father(){}; ~Father(){};};class Son:public Father{public: Son(){}; ~Son(){};};int main(){ Father *pfath...

weixin_34241036的博客 449

虚函数析构函数(内存泄漏)(12)

#ifndef A_H #define A_H #include <iostream> using namespace std; class A{ public: A(); ~A(); }; #endif A_H #include "A.h" A::A() { cout << "A::A()" << endl; } A::~A() { cou...

xt18971492243的博客 277
上一篇: 为什么你的对象无法在编译期初始化?constexpr构造函数常见陷阱全曝光
下一篇: 【C++高手进阶必看】:掌握C++14二进制字面量,告别位运算混乱时代
MessyInk
博客等级 码龄11年 136粉丝 1992原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值