[翻译] Effective C++, 3rd Edition, Item 18: 使 interfaces(接口)易于正确使用,而难以错误使用

基于Zynq的便携式γ能谱仪设计与实现 数字多道分析器(DMCA)是核辐射能谱测量的核心设备,其本质是将探测器输出的模拟脉冲按幅度数字化分道,构建能量-计数分布曲线,从而支撑放射性核素识别与定量分析。其技术原理依赖高速采样、数字滤波成形、基线恢复与峰值提取等关键信号处理环节,具备高分辨率、优线性度与强抗干扰能力。在环境监测、核安全巡检与野外地质勘探等场景中,对低功耗、小型化、实时性提出严苛要求。本方案采用Xilinx Zynq-7020异构SoC架构,融合FPGA实时数字信号处理与ARM嵌入式控制,实现软硬协同优化,兼顾算法精度与工程落地性,为国 阅读详情

 

Item 18: 使 interfaces(接口)易于正确使用,而难以错误使用

作者:Scott Meyers

译者:fatalerror99 (iTePub's Nirvana)

发布:http://blog.youkuaiyun.com/fatalerror99/

C++ 被淹没于 interfaces(接口)中。function interfaces(函数接口)、class interfaces(类接口)、template interfaces(模板接口)。每一个 interface(接口)都是客户和你的代码交互的一种方法。如果你在和通情达理的人打交道,那些客户也想做好工作。他们想要正确使用你的 interfaces(接口)。在这种情况下,如果他们错误地使用了它,就说明你的 interface(接口)至少有部分是不完善的。在理想情况下,如果一个 interface(接口)的一种用法的尝试不符合客户的预期,代码将无法编译,反过来,如果代码可以编译,那么它做的就是客户想要的。

开发易于正确使用,而难以错误使用的 interfaces(接口)要求你考虑客户可能造成的各种错误。例如,假设你正在为一个代表日期的 class 设计 constructor(构造函数):

class Date {
public:
  Date(int month, int day, int year);
  ...
};

乍一看,这个 interface(接口)似乎是合乎情理的(至少在美国),但是客户可能很容易地造成两种错误。首先,他们可能会以错误的顺序传递 parameters(参数):

Date d(30, 3, 1995);              // Oops! Should be "3, 30" , not "30, 3"

第二,他们可能传递一个非法的月或日的数字:

Date d(3, 40, 1995);              // Oops! Should be "3, 30" , not "3, 40"

(后面这个例子看上去好像很愚蠢,但是想想键盘上,4 就在 3 的旁边,这种 "off by one" 类型的错误并不罕见。)(上面这个例子原文有误,根据作者网站勘误更改——译者注。)

很多客户错误都可以通过新类型的引入来预防。确实,type system(类型系统)是你阻止那些不合理的代码通过编译的主要支持者。在当前情况下,我们可以引入简单的 wrapper types(包装类型)来区别日,月和年,并将这些类型用于 Data constructor(构造函数)。

struct Day {            struct Month {                struct Year {
  explicit Day(int d)     explicit Month(int m)         explicit Year(int y)
  :val(d) {}              :val(m) {}                    :val(y){}

  int val;                int val;                      int val;
};                      };                            };

class Date {
public:
 Date(const Month& m, const Day& d, const Year& y);
 ...
};
Date d(30, 3, 1995);                      // error! wrong types

Date d(Day(30), Month(3), Year(1995));    // error! wrong types

Date d(Month(3), Day(30), Year(1995));    // okay, types are correct

将 Day,Month 和 Year 做成可以封装数据的羽翼丰满的 classes 比上面的简单地使用 structs 更好(参见 Item 22),但是即使是 structs 也足够证明明智的新类型引入在阻止 interface(接口)的错误使用方面能工作得非常出色。

只要将正确的类型放在适当的位置,它往往能合理地限定那些类型的值。例如,月仅有 12 个合法值,所以 Month 类型应该反映这一点。做到这一点的一种方法是用一个 enum(枚举)来代表月,但是 enums(枚举)不像我们希望的那样是 type-safe(类型安全)的。例如,enums(枚举)能被作为 ints 使用(参见 Item 2)。一个更安全的解决方案是预先确定所有合法的 Months 的集合:

class Month {
public:
  static Month Jan() { return Month(1); }   // functions returning all valid
  static Month Feb() { return Month(2); }   // Month values; see below for
  ...                                       // why these are functions, not
  static Month Dec() { return Month(12); }  // objects

  ...                                       // other member functions

private:
  explicit Month(int m);                    // prevent creation of new
                                            // Month values

  ...                                       // month-specific data
};
Date d(Month::Mar(), Day(30), Year(1995));

如果用 functions 代替 objects 来代表特定月的主意让你感到奇怪,那可能是因为你忘了 non-local static objects(非局部静态对象)的初始化的可靠性是值得怀疑的。Item 4 能唤起你的记忆。

防止可能的客户错误的另一个方法是限制对一个类型能够做的事情。施加限制的一个通常方法就是加上 const。例如,Item 3 阐释了使 operator* 的返回类型 const-qualifying(具备 const 资格)是如何能够防止客户对 user-defined types(用户定义类型)犯下这样的错误:

if (a * b = c) ...                    // oops, meant to do a comparison!

实际上,这仅仅是另一条使类型易于正确使用而难以错误使用的普遍方针的一种表现:除非你有很棒的理由,否则就让你的类型的行为与 built-in types(内建类型)保持一致。客户已经知道像 int 这样的类型有怎样的行为,所以你应该努力使你的类型的行为无论何时都同样合理。例如,如果 a 和 b 是 ints,给 a*b 赋值是非法的。所以除非有一个非常棒理由背离这种行为,否则,对你的类型来说这样做也应该是非法的。拿不定主意时,就像 ints 那样做。

避免和 built-in types(内建类型)毫无理由的 incompatibilities(不兼容性)的真正原因是为了提供行为一致的 interfaces(接口)。很少有特性比 consistency(一致性)更有可能导出易于正确使用的 interfaces(接口),也很少有特性比 inconsistency(不一致性)更有可能导出令人郁闷的 interfaces(接口)。STL containers(STL 容器)的 interfaces(接口)在很大程度上(虽然并不完美)是一致的,而这使得它们相当易于使用。例如,每一种 STL containers(STL 容器)都有一个名为 size 的 member function(成员函数)可以知道这个 container(容器)中有多少 objects。与此对比的是 Java,在那里你对 arrays(数组)使用 length property(属性),对 Strings 使用 length method(方法),而对 Lists 却要使用 size method(方法),在 .NET 中,Arrays 有一个名为 Length 的 property(属性),而 ArrayLists 却有一个名为 Count 的 property(属性)。一些开发人员认为 integrated development environments (IDEs)(集成开发环境)能补偿这些琐细的 inconsistencies(不一致),但他们错了。inconsistency(不一致)在开发者工作中强加的精神负担是任何 IDE 都无法完全消除的。

任何一个要求客户记住做某些事情的 interface(接口)都是倾向于错误使用的,因为客户可能忘记做那些事情。例如,Item 13 引入了一个 factory function(工厂函数),它返回一个指向动态分配的 Investment hierarchy(继承体系)中的 objects(对象)的指针。

Investment* createInvestment();       // from Item 13; parameters omitted
                                      // for simplicity

为了避免 resource leaks(资源泄漏),从 createInvestment 返回的指针最后必须被删除,但这就为至少两种类型的客户错误创造了机会:没有删除指针,或删除同一个指针一次以上。

Item 13 展示了客户可以将 createInvestment 的返回值存入一个类似 auto_ptr 或 tr1::shared_ptr 的 smart pointer(智能指针)的方式,从而将使用 delete 的职责交给 smart pointer(智能指针)。但是如果客户忘记使用 smart pointer(智能指针)呢?在很多情况下,一个更好的 interface(接口)策略会通过让 factory function(工厂函数)首先返回一个 smart pointer(智能指针)而预先解决问题:

std::tr1::shared_ptr<Investment> createInvestment();

这就从根本上强制客户将返回值存入一个 tr1::shared_ptr,几乎完全消除了当底层的 Investment object 不再使用的时候却忘记删除的可能性。

实际上,返回一个 tr1::shared_ptr 使得一个 interface(接口)设计者预防许多其它的与资源泄漏释放相关的客户错误成为可能,因为,就像 Item 14 阐述的:当一个 smart pointer(智能指针)被创建的时候,tr1::shared_ptr 允许将一个 resource-release function(资源释放函数)——一个 "deleter" ——绑定到这个 smart pointer(智能指针)上。(auto_ptr 则没有这个能力。)

假设从 createInvestment 得到一个 Investment* 指针的客户期望将这个指针传给一个名为 getRidOfInvestment 的函数,而不是对它使用 delete。这样一个 interface(接口)又为一种新的客户错误打开了大门,这就是客户可能使用了错误的 resource-destruction mechanism(资源析构机制)(也就是说,用了 delete 而不是 getRidOfInvestment)。createInvestment 的实现通过返回一个在其 deleter 上绑定了 getRidOfInvestment 的 tr1::shared_ptr 能够预防这样的问题。

tr1::shared_ptr 提供了一个取得两个 arguments(实参)(要被管理的指针和当引用计数变为零时要调用的 deleter)的 constructor(构造函数)。这里展示了创建一个以 getRidOfInvestment 作为 deleter 的 null tr1::shared_ptr 的方法:

std::tr1::shared_ptr<Investment>      // attempt to create a null
  pInv(0, getRidOfInvestment);        // shared_ptr with a custom deleter;
                                      // this won't compile

唉呀,这不是合法的 C++。tr1::shared_ptr constructor(构造函数)坚决要求它的第一个参数是一个指针,而 0 不是一个指针,它是一个 int。当然,它 convertible(能转换)为一个指针,但那在当前情况下并不够好,tr1::shared_ptr 坚决要求一个真正的指针。用一个 cast(强制转型)解决个问题:

std::tr1::shared_ptr<Investment>      // create a null shared_ptr with
  pInv(static_cast<Investment*>(0),   // getRidOfInvestment as its
         getRidOfInvestment);         // deleter; see Item 27 for info on
                                      // static_cast

据此,实现返回一个以 getRidOfInvestment 作为其 deleter 的 tr1::shared_ptr 的 createInvestment 的代码看起来就像这个样子:

std::tr1::shared_ptr<Investment> createInvestment()
{
  std::tr1::shared_ptr<Investment> retVal(static_cast<Investment*>(0),
                                          getRidOfInvestment);

  retVal = ... ;                         // make retVal point to the
                                         // correct object

  return retVal;
}

当然,如果将被 retVal 管理的 raw pointer(裸指针)可以在创建 retVal 时被确定,最好是将这个 raw pointer(裸指针)传给 retVal 的 constructor(构造函数),而不是将 retVal 初始化为 null 然后再赋值给它。至于方法上的细节,参考 Item 26。(此段原文有误,根据作者网站勘误更改——译者注。)

tr1::shared_ptr 的一个特别好的特性是它自动 per-pointer(逐指针)地使用 deleter 以消除另一种潜在的客户错误——“cross-DLL 问题。”这个问题发生在这种情况下:一个 object 在一个 dynamically linked library (DLL)(动态链接库)中通过 new 被创建,在另一个不同的 DLL 中被删除。在许多平台上,这样的 cross-DLL new/delete 对会导致运行时错误。tr1::shared_ptr 避免了这个问题,因为它的缺省的 deleter 只将 delete 用于这个 tr1::shared_ptr 被创建的同一个 DLL 中。这就意味着,例如,如果 Stock 是一个继承自 Investment 的 class,而且 createInvestment 被实现如下,

std::tr1::shared_ptr<Investment> createInvestment()
{
  return std::tr1::shared_ptr<Investment>(new Stock);
}

返回的 tr1::shared_ptr 能在 DLLs 之间进行传递,而不必关心 cross-DLL 问题。指向这个 Stock 的 tr1::shared_ptrs 将保持对“当这个 Stock 的引用计数变为零的时候,哪一个 DLLs 的 delete 应该被使用”的跟踪。

这个 Item 不是关于 tr1::shared_ptr 的——而是关于使接口易于正确使用,而难以错误使用的——但 tr1::shared_ptr 正是这样一个消除某些客户错误的简单方法,它大体上值回了使用它的成本。最通用的 tr1::shared_ptr 实现来自于 Boost(参见 Item 55)。Boost 的 shared_ptr 的大小是一个 raw pointer(裸指针)的两倍,为簿记和 deleter-specific(deleter 专用)数据使用动态分配内存,当调用它的 deleter 时使用一个 virtual function(虚拟函数)来调用,在一个它认为是 multithreaded(多线程)的应用程序中,每当改变引用计数,会导致 thread synchronization(线程同步)开销。(你可以通过定义一个 preprocessor symbol(预处理符号)来使多线程支持失效。)在缺点方面,它比一个 raw pointer(裸指针)大,比一个 raw pointer(裸指针)慢,而且要使用辅助的动态内存。在许多应用程序中,这些附加的运行时开销并不显著,而对客户错误的减少却是每一个人都看得见的。

Things to Remember

  • 好的 interfaces(接口)是易于正确使用,而难以错误使用的。你应该在你的所有 interfaces(接口)中为这个特性努力。
  • 使易于正确使用的方法包括在 interfaces(接口)和 behavioral compatibility(行为兼容性)上与 built-in types(内建类型)保持一致。
  • 预防错误的方法包括创建新的类型,限定类型的操作,约束 object 的值,以及消除客户的资源管理职责。
  • tr1::shared_ptr 支持自定义 deleter。这可以防止 cross-DLL 问题,能用于自动解锁互斥体(参见 Item 14)等。
ParallelsDesktop 安装 CentOS-6.9-x86_64-minimal 教程 安装参考 tools没做 想安装的可以参考这个 mac 本机环境: 系统:macOS Catalina version 10.15.6 虚拟机软件:parallels Desktop 15 for Mac( Parallels Desktop-15.1.4(47270)) Centos镜像: CentOS-6.9-x86_64-minimal.iso https://mirrors.aliyun.com/centos-vault/6.8/isos/x86_64/ http://vault.centos. 阅读详情

相关推荐

网络设备调试指南:如何用MDIO Clause22/45协议读写Marvell MV88E6390寄存器

本文深入解析了如何通过MDIO Clause 22/45协议对Marvell MV88E6390交换芯片进行寄存器读写调试。文章详细对比了两种协议的本质区别与适用场景,并重点阐述了MV88E6390的直接与间接寻址策略,提供了实战代码示例与关键调试技巧,帮助网络工程师高效解决配置与通信问题。

tequila的博客 519

Effective C++ Item 18 让接口容易被正确使用,不易被误用

经验1:好的接口很容易被正确使用,不容易被误用。你应该在你的所有接口中努力达成这些性质。 经验2:“促进正确使用”的办法包括接口的一致性,以及与内置类型的行为兼容 经验3:“阻止误用”的办法包括建立新类型、限制类型上的操作,束缚对象值,以及消除客户的资源管理责任。

714

Windows 10 本地开发环境:用 ShardingSphere-Proxy 5.4.1 快速搭建 MySQL 分库分表测试环境

本文详细介绍了在Windows 10系统中使用ShardingSphere-Proxy 5.4.1快速搭建MySQL分库分表测试环境的完整教程。从环境准备、MySQL配置到ShardingSphere-Proxy的核心设置,逐步指导开发者完成本地开发环境的搭建,并提供了分片策略详解和常见问题排查方法,帮助开发者高效验证分库分表功能。

weixin_28366053的博客 214

Effective C++ 读书笔记 Item18 让接口容易被正确使用,不易被误用

现在我们来到软件设计的话题中。软件设计就是让软件做你想做的事,软件设计一定需要接口(interface)设计,最后用C++实现。我们今天讨论可能是其中最重要的一条守则,把你的接口设计得容易用对,不容易用错。讨论完这一条,会引出更多关于软件设计的话题,比如效率(efficiency),封装(encapsulation),可维护性(maintainability)和一些惯例(convention)。 ...

Vermont_的博客 234

STM32+OV7670实战:5步搞定低成本人脸识别门禁系统(附完整代码)

本文详细介绍了基于STM32单片机和OV7670摄像头构建低成本离线人脸识别门禁系统的完整实战方案。文章从硬件选型、电路设计避坑入手,逐步讲解了图像采集优化、轻量级人脸检测与LBP特征提取策略,并提供了离线人脸库管理、特征比对以及系统集成的具体实现方法,附有核心代码示例,旨在帮助开发者快速实现可落地的嵌入式视觉应用。

kubernetes8ctl的博客 568

SARScape实战:集成GACOS数据优化InSAR大气校正全流程

本文详细介绍了如何在SARScape软件中集成GACOS数据,以优化InSAR大气校正的全流程。通过实战步骤,从GACOS数据申请、下载、导入,到在单景干涉图和SBAS-InSAR流程中应用,有效剥离大气相位延迟,显著提升形变监测结果的精度与可靠性,实现从“雾里看花”到“拨云见日”的转变。

weixin_28419039的博客 402

Effective Modern C++翻译系列之Item18

Item18:Use std::unique_str for exclusive-ownership resource management. 当你需要一个智能指针的时候,std::unique_ptr一般是最容易用到的一种。有理由假设,在默认情况下,std::unique_ptr和原生指针有相同的大小以及大部分操作符(包括解引用操作符),它们执行完全相同的指令。这意味着你可以在存储和循环频繁发

种树种树 459

ISCE2+MintPy环境搭建实战:用Anaconda五分钟搞定InSAR处理全家桶

本文提供了一份详细的ISCE2+MintPy环境安装教程,旨在帮助InSAR处理初学者快速搭建开发环境。通过使用Anaconda创建虚拟环境并配置国内镜像,用户可在五分钟内一键安装ISCE2和MintPy全家桶,有效解决依赖冲突和版本兼容性问题,让用户能专注于数据处理本身。

2y3u4i5o6p的博客 1005

深挖C++:类和对象(中)

(先进后出)

xys_678的博客 254

Python 使用Pygame库实现足球游戏:创建一个球员和一个足球,并使玩家能够控制球员的移动。游戏将包括碰撞检测、简单的物理模拟,以及基本的用户输入处理

本文将介绍如何使用Python和Pygame库创建一个简单的足球游戏。我们将搭建一个基本的游戏环境,创建一个球员和一个足球,并使玩家能够控制球员的移动。游戏将包括碰撞检测、简单的物理模拟,以及基本的用户输入处理。这个简单的足球游戏展示了Pygame的一些基本功能。虽然这是一个简单的游戏,但它包含了创建游戏循环、用户输入处理、物理模拟、碰撞检测等重要概念。

程序熊的博客 743

手把手教你RK3568 MIPI屏驱动适配,纯干货!

RK3568 作为一款高性能的多媒体处理器,在嵌入式领域中备受瞩目。它采用了先进的 22nm 制程工艺,搭载四核 Cortex-A55 处理器,这种架构为芯片提供了高效的功耗比,使其在运行各种复杂任务时,既能保证性能,又能有效控制功耗。在实际应用中,无论是多任务处理还是运行大型应用程序,RK3568 都能凭借其四核 Cortex-A55 处理器,实现流畅的操作体验,满足智能设备对高性能和低功耗的需求。

远程部署调试 运行安装 项目调试 二次开发 项目技术新 持续迭代 部分源码免费分享 4071

C++移动构造函数详解

移动构造函数是C++11引入的一种特殊构造函数,用于从临时对象(右值)"窃取"资源来初始化新对象,而不是进行昂贵的深拷贝。char* data;public:// 移动构造函数:参数是右值引用 &&// 关键:把源对象的资源置空。

拒绝AI文,努力在AI时代写出感动人心的好文章 394

Y-Branch and a closed y-branch loop

双臂后面的区域,我们将它的双臂使用一个波导进行了连接,使得它本身形成了一个闭合回路,因此,该结构被称作。它们均是用来对经过它们的光束能量进行分割的一种器件。首先,我们知道一点,在光波导层面,今天给大家介绍一下,什么是。

u011699626的博客 632

ThunderKittens 深度解析:一个不基于 MLIR 的 C++ 模板 GPU DSL

Triton 是"让更多人能写 GPU kernel",ThunderKittens 是"让会写的人写得更爽"。前者用 MLIR 换易用性,后者用 C++ 模板换可控性。它们不是替代关系,而是覆盖了 GPU 编程光谱的两端。ThunderKittens 的出现,本质上是对"GPU DSL 必须基于 MLIR"这一默认假设的挑战。编译期类型系统本身就可以是一个强大的 DSL 基础设施,不需要中间 IR,不需要黑盒 pass,也能实现 tile 级抽象和零运行时开销。

Maxwell_Newton的博客 349

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

跟我学c++中级篇—类型定义的方式

本文系统阐述了编程中类型定义的重要性及c++中的实现方式。重点对比了宏定义、typedef与modern using三种机制,指出using在可读性、灵活性和模板支持上的优势,推荐优先使用。同时提醒开发者注意别名滥用、类型歧义、错误信息冗长等问题,强调统一规范与合理设计。最终结论:在现代c++开发中,应以using为主,兼顾简洁性与可维护性,避免陷入命名混乱与编译困境。

fpcc的专栏 88

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

【C++——类和对象(上)】筑基篇:以封装奠定面向对象之基

本文系统梳理C++类与对象的核心知识点,涵盖类的定义、访问限定符(public/private)、类作用域、对象实例化及内存布局。重点解析封装思想、this指针机制、空类大小为1字节的原因,以及类与对象在内存中的存储差异。通过对比C语言结构体与C++类,揭示面向对象设计的优势:数据保护、接口统一、命名隔离与代码可维护性提升。内容由浅入深,适合作为学习笔记与复习参考。

2602_95684935的博客 497

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

C++ 函数模版

模板参数:● template ,T 就是类型占位符,名字可以自定义,习惯用T● 占位符可以在函数返回值、形参、函数内部当作类型使用使用要点模板代码一般写在头文件:编译器需要看到完整模板源码,才能在每个编译单元完成实例化全局函数、类内成员函数都可以写成模板实例化发生在编译阶段,不是运行时隐式实例化:调用时编译器自动推导实参类型,生成对应版本函数。

2501_94041724的博客 307

C++ 运行时多态与虚函数机制全面剖析【面试重点】

构成C++ 运行时多态必须是基类的指针或者引用调用虚函数。被调用的函数必须是虚函数,并且派生类必须对该虚函数完成重写/覆盖(Override)。只有基类的指针或引用才能既指向基类对象,又指向派生类对象(切片机制);而只有完成了虚函数重写,派生类与基类才具备不同的函数行为,达到“指向谁就调用谁”的效果。在类成员函数的前面加上virtual关键字修饰,该成员函数就成为了虚函数。public:// 成员函数前加 virtual 修饰,声明为虚函数。

Fuyo_0209的博客 450

#SQLite 数据库笔记一:(概念 / 终端指令 / SQL 语句 / C 编程 / 回调函数)

数据库 = 数据的仓库,假设数据是海量。能力说明存储数据持久化保存,程序退出数据还在统计数据、分组、排序数据管理增、删、改、查(CRUD)嵌入式设备上也会用数据库(单片机网关、路由器、工业 HMI 都常见),因为 sqlite 体积小、无需服务进程、单文件即可。数据库 = 库 > 表 > 记录(行) > 字段(列)sqlite3 = 开源、C 写的、单文件、免安装、最多 2T 的嵌入式关系型数据库。

lwq20051110的博客 251

1-10 PostgreSQL中多表连接全解:inner/left/right/full/cross join

本文基于 PostgreSQL 15+ 完整拆解 5 种主流连接:内连接、左连接、右连接、全连接、笛卡尔连接。结合可落地的测试数据,演示每种连接的执行逻辑、返回结果,重点剖析 NULL 值对 JOIN 匹配的核心影响,彻底解决多表连接数据丢失、匹配异常、结果错乱的问题。

zhangjw34的专栏 105

【C++ 基础入门】C++继承(下):问题、底层原理与组合

C++继承(菱形继承的问题、虚继承原理、继承与组合、构造顺序)

2601_96587588的博客 802

蓝桥杯·全国青少年信息素养大赛·电子学会Python/C++考级 备考:莫队算法离线区间查询详解

备赛进行时:第十八届蓝桥杯软件赛报名已于 2026-10-08 10:00 开启、12-18 14:00 截止,省赛定在 2027-04-10(C/C++·Python 程序设计 9:00–13:00);中国电子学会 2026 年 12 月软件编程(C/C++ 一级至十级、Python 一级至六级)考级报名 9/23–12/2 16:00、统考 12-12;全国青少年信息素养大赛 2026—2027 赛季算法应用主题赛也已进入复盘练兵窗口。

IT_Scratch的博客 170

c++ explicit关键字详解

explicit。

拒绝AI文,努力在AI时代写出感动人心的好文章 151

825 mW 顶上 212 °C:ASM491S 的 105 °C/W、250 mA 短路电流与热关断

25 °C 环境里结温 34.1 °C,125 °C 环境里结温 134.1 °C——后者已经离 150 °C 只有 16 °C 了,但还在范围内。换个角度看同一件事:从 25 °C 和从 125 °C 起算,温升都是 86.6 °C,但一个到 111.6 °C(还在范围内),一个到 211.6 °C(远远超限)。这个算例里 20 °C/W 是我假设的,实际值取决于机壳材料、密封程度、有没有风扇,跨度可以从 5 °C/W 到 50 °C/W 以上。外面 50 °C 的机箱,盒内就是 63.9 °C。

ANSILIC的博客 393

《C++ 项目:手写大模型接入 SDK》Gemini接口设计(上):初始化、全量响应实现和测试

本文系统完成了Gemini模型通过OpenAI兼容API的接入开发,基于Apifox验证接口规范,设计并实现GeminiProvider类,涵盖初始化、状态检测、全量响应等核心功能。重点处理了代理配置强制校验、Bearer鉴权、JSON序列化与响应解析等工程细节,并通过GTest与CMake完成单元测试,验证链路可用性。项目遵循策略模式,保持与DeepSeek、ChatGPT等模型的统一抽象接口,显著提升SDK可扩展性。

2501_91275995的博客 398

【容斥原理计数】题解:P9489 ZHY的表示法_容斥原理_计数问题_前缀和问题转化_算法竞赛C++

给定 $ n $ 个正整数,求区间 $[l,r]$ 中有多少正整数 $ x $ 可表示为 $ \sum \lfloor \frac{y}{x_i} \rfloor $。通过二分确定最大 $ y $,转化为求 $ 1 \sim H $ 中是某些 $ x_i $ 倍数的数的个数,利用容斥原理与 DFS 枚举子集计算,结合 LCM 预判剪枝及去重优化,时间复杂度 $ O(2^n \log V) $,可高效处理 $ r \le 10^9 $ 的数据。

YLCHUP的博客 106
上一篇: [翻译] Effective C++, 3rd Edition, Item 17: 在 standalone statements(独立语句)中将 new 出来的 objects(对象)存入 smart pointers(智能指针)
下一篇: [翻译] Effective C++, 3rd Edition, Item 19: 视 class design(类设计)为 type design(类型设计)
fatalerror99
博客等级 码龄24年 166粉丝 20原创
评论 7
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值