[翻译] Effective C++, 3rd Edition, Item 28: 避免返回 object 内部构件的 "handles"(“句柄”)

2026 具身智能 VLA/WAM 全栈学习与训练路线:从动作建模、SFT、RL 到世界模型的 RTX PRO 6000 96GB 单卡实战指南 我会把这张表做成“”而不是只列论文名:先核对每个模型截至的公开代码、训练目标和数据接口,再单独给你一套。对于没有公开、只有推理代码或训练细节不完整的模型,我会明确标出来,避免把“论文里提到”误写成“可复现”。目前有一个重要更新:。截至今天 NVIDIA 官方开源主线已经是换成 Cosmos-Reason2-2B/Qwen3-VL 架构,动作端仍是连续路线,而且官方明确给出单卡微调时默认只训练,峰值显存约。所以你的 96GB 单卡对 GR00T SFT 非常宽裕。可以。下面我按,把它整理成一张真正面向“ 阅读详情

Item 28: 避免返回 object 内部构件的 "handles"(“句柄”)

作者:Scott Meyers

译者:fatalerror99 (iTePub's Nirvana)

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

假设你正在一个与矩形有关的应用程序上工作。每一个矩形都可以用它的左上角和右下角表示出来。为了将一个 Rectangle object 保持在较小状态,你可能决定定义 Rectangle 区域的那些点不应该存储在 Rectangle 自身之中,更合适的做法是放在一个由 Rectangle 指向的辅助的结构体中:

class Point {                      // class for representing points
public:
  Point(int x, int y);
  ...

  void setX(int newVal);
  void setY(int newVal);
  ...
};

struct RectData {                    // Point data for a Rectangle
  Point ulhc;                        // ulhc = " upper left-hand corner"
  Point lrhc;                        // lrhc = " lower right-hand corner"
};

class Rectangle {
  ...

private:
  std::tr1::shared_ptr<RectData> pData;          // see Item 13 for info on
};                                               // tr1::shared_ptr

由于 Rectangle 的客户需要能操控一个 Rectangle 的区域,因此这个 class 提供了 upperLeft 和 lowerRight 函数。然而,Point 是一个 user-defined type(用户定义类型),所以,留心 Item 20 的关于在典型情况下,以传引用的方式传递 user-defined type(用户定义类型)比传值的方式更加高效的观点,这些函数返回引向底层 Point objects 的引用:

class Rectangle {
public:
  ...
  Point& upperLeft() const { return pData->ulhc; }
  Point& lowerRight() const { return pData->lrhc; }
  ...
};

这个设计可以编译,但它是错误的。实际上,它是自相矛盾的。一方面,upperLeft 和 lowerRight 被声明为 const member functions(成员函数),因为它们被设计成仅仅给客户提供一个获得 Rectangle 的点的方法,而不允许客户改变这个 Rectangle(参见 Item 3)。另一方面,两个函数都返回引向 private internal data(私有内部数据)的引用——调用者可以用来修改那些 internal data(内部数据)的引用!例如:

Point coord1(0, 0);
Point coord2(100, 100);

const Rectangle rec(coord1, coord2);     // rec is a const rectangle from
                                         // (0, 0) to (100, 100)

rec.upperLeft().setX(50);                // now rec goes from
                                         // (50, 0) to (100, 100)!

请注意这里,upperLeft 的调用者是如何能够利用返回的引向 rec 内部 Point data members(数据成员)的引用来改变这个成员的。但是 rec 却被假设为 const!

这直接引出两条教训。第一,一个 data member(数据成员)只能被封装到具有最高可访问级别的函数能返回一个引向它的引用的程度。在当前情况下,虽然 ulhc 和 lrhc 被它们的 Rectangle 认为是 private(私有)的(此处原文有误,根据作者网站勘误修改——译者注),但它们还是被有效地公开了,因为 public 函数 upperLeft 和 lowerRight 返回了引向它们的引用。第二,如果一个 const member function(成员函数)返回一个引用,引向一个与某个 object 有关并存储在这个 object 自身之外的数据,这个函数的调用者就可以改变那个数据(这正是 bitwise constness(二进制位常量性)的局限性(参见 Item 3)的一个副作用)。

我们已做的每件事都涉及到返回引用的 member functions(成员函数),但是,如果它们返回指针或者迭代器,因为同样的原因也会存在同样的问题。引用,指针,和迭代器都是 handles(句柄)(持有其它 objects 的方法),而返回一个 object 的 internals(内部构件)的 handle(句柄)总是面临危及 object 的 encapsulation(封装)的风险。就像我们看到的,它同时还能导致允许 const member functions(成员函数)改变一个 object 的状态。

我们通常认为一个 object 的 "internals"(“内部构件”)就是它的 data members(数据成员),但是不能被普通公众访问的 data members(成员函数)(也就是说,它是 protected 的或 private 的)也是 object 的 internals(内部构件)的一部分。同样,不要返回它们的 handles(句柄)也很重要。这就意味着你绝不应该有一个 member function(成员函数)返回一个指向拥有较小的可访问级别的 member function(成员函数)的指针。如果你这样做了,它的有效可访问级别就会与那个拥有较大的可访问级别的函数相同,因为客户能够得到指向这个拥有较小的可访问级别的函数的指针,然后就可以通过这个指针调用这个函数。

然而,返回指向 member functions(成员函数)的指针的函数是难得一见的,所以让我们把注意力返回到 Rectangle class 和它的 upperLeft 和 lowerRight member functions(成员函数)上。我们在这些函数中挑出来的问题都只需简单地将 const 用于它们的返回类型就可以消除:

class Rectangle {
public:
  ...
  const Point& upperLeft() const { return pData->ulhc; }
  const Point& lowerRight() const { return pData->lrhc; }
  ...
};

通过这个修改过的设计,客户可以读取定义一个矩形的 Points,但他们不能写它们。这就意味着将 upperLeft 和 lowerRight (此处原文有误,根据作者网站勘误修改——译者注)声明为 const 不再是一句空话,因为它们不再允许调用者改变 object 的状态。至于 encapsulation(封装)的问题,我们总是故意让客户看到组成一个 Rectangle 的 Points,所以这是 encapsulation(封装)的一个故意的放松之处。更重要的,它是一个 limited(有限)的放松:只有读访问是被这些函数准许的,写访问依然被禁止。

虽然如此,upperLeft 和 lowerRight 仍然返回一个 object 的 internals(内部构件)的 handles(句柄),而这在其它方面可能是有问题的。特别是,这会导致 dangling handles(空悬句柄):引用了不再存在的 objects 的构件的 handles(句柄)。这种消失的 objects 的最常规的来源就是函数返回值。例如,考虑一个函数,以一个矩形的形式返回一个 GUI object 的 bounding box:

class GUIObject { ... };

const Rectangle                             // returns a rectangle by
  boundingBox(const GUIObject& obj);        // value; see Item 3 for why
                                            // return type is const

现在,考虑客户可能会如何使用这个函数:

GUIObject *pgo;                             // make pgo point to
...                                         // some GUIObject

const Point *pUpperLeft =                   // get a ptr to the upper
  &(boundingBox(*pgo).upperLeft());         // left point of its
                                            // bounding box

对 boundingBox 的调用会返回一个新建的临时的 Rectangle object。这个 object 没有名字,所以让我们就称它为 temp。于是 upperLeft 就在 temp 上被调用,这个调用返回一个引向 temp 的一个内部构件的引用,特别是,它是由 Points 构成的。随后 pUpperLeft 指向这个 Point object。到此为止,一切正常,但是我们无法继续了,因为在这个语句的末尾,boundingBox 的返回值—— temp ——被销毁了,这将间接导致 temp 的 Points 的析构。接下来,剩下 pUpperLeft 指向一个已经不再存在的 object;pUpperLeft 空悬在创建它的语句的末尾!

这就是为什么任何一个返回一个 object 的内部构件的 handle(句柄)的函数都是危险的。这与那个 handle(句柄)是指针,引用,还是迭代器没什么关系。它与是否受到 cosnt 的限制没什么关系。这与那个 member function(成员函数)返回的 handle(句柄)本身是否是 const 没什么关系。全部的问题在于一个 handle(句柄)被返回了,因为一旦这样做了,你就面临着这个 handle(句柄)比它引用的 object 更长寿的风险。

这并不意味着你永远不应该让一个 member function(成员函数)返回一个 handle(句柄)。有时你必须如此。例如,operator[] 允许你从 strings 和 vectors 中抽出单独的元素,而这些 operator[]s 就是通过返回引向 containers(容器)中的数据的引用来工作的(参见 Itme 3)——当 containers(容器)本身被销毁,数据也将销毁。尽管如此,这样的函数属于特例,而不是惯例。

Things to Remember

  • 避免返回 object internals(对象内部构件)的 handles(句柄)(引用,指针,或迭代器)。这样会提高 encapsulation(封装),帮助 const member functions(成员函数)产生 cosnt 效果,并将最小化 dangling handles(空悬句柄)产生的可能性。

 

机器人视觉仿真软件:PCL (Point Cloud Library)_(8).点云分割技术 点云分割技术在机器人视觉处理中起着至关重要的作用,通过不同的分割方法可以有效地将点云数据中的不同物体或区域分离出来。PCL提供了丰富的分割算法,包括基于平面的分割、基于聚类的分割、基于模型的分割和基于条件的分割等。每种方法都有其适用的场景和优缺点,选择合适的方法可以显著提高点云处理的效率和准确性。希望本节的内容能够帮助读者更好地理解和应用点云分割技术。 阅读详情

相关推荐

RM机器人麦轮底盘实战:从零搭建到PID调参全记录(附避坑指南)

本文详细记录了RM机器人麦轮底盘从零搭建到PID调参的全过程,涵盖硬件组装、开发环境搭建、底盘解算和PID调参等关键步骤,并附有实用的避坑指南。特别针对麦轮控制、底盘解算和电机调试等核心问题提供了专业解决方案,帮助开发者快速提升机器人性能。

bush的博客 379

Effective c++之Item 28: 避免返回对象内部构件的“句柄”

假设你正在一个包含矩形的应用程序上工作。每一个矩形都可以用它的左上角和右下角表示出来。为了将一个 Rectangle 对象保持在较小状态,你可能决定那些点的定义的域不应该包含在 Rectangle 本身之中,更合适的做法是放在一个由 Rectangle 指向的辅助的结构体中: class Point { // class for representing points public: Poi

janeqi1987的专栏 348

要配置西门子G120XA变频器实现**端子启停**和**Modbus RTU(485)频率给定

如有问题,可通过STARTER软件在线诊断Modbus通讯状态。要配置西门子G120AX变频器实现。

微:13763355074 4856

Effective C++ Item 28 避免返回对象内部数据的引用或指针

本文为senlie原创。转载请保留此地址:http://blog.youkuaiyun.com/zhengsenlie Item 31 经验:避免返回handles(包含 references、指针、迭代器)指向对象内部。遵守这个条款可添加封装性。 帮助 const 成员函数的行为像个 const。并将发生“虚吊号码牌”(dangling handles)的可能性降至最低。 演示样...

weixin_34133829的博客 136

全局子程序 参数调用

为什么要子程序: 为了实现程序结构化,我们尽量使用不同功能的功能块来实现一些特定的功能, 子程序接口: 使用过程的注意事项,尤其是数组使用时的注意事项 从一个主程序中可以将参数传递到局部或全局子程序和函数中。 怎样传递参数有 2 种方式: 作为 IN 参数 变量值在主程序中保持不变。 这种传递方式也称为“ 值传递 (Call by Value)”。 作为 OUT 参数 子程序读取并更改该值,然后将新值写回到主程序中。 这种传递方式也称为“Call by Reference”。 举例说明 1 DEF MY

Eric_Yang1024的博客 1095

YOLOv8n行人检测实战:从数据集准备到模型训练

本文详细介绍了使用YOLOv8n进行行人检测的完整流程。首先阐述了YOLOv8的优势:高速推理(300+FPS)、更高精度、易用性和轻量化(仅6MB)。接着通过Docker搭建GPU训练环境,配置32GB共享内存避免数据加载问题,并安装必要的框架和OpenCV组件。数据集采用COCO2017标注格式,包含归一化坐标的YOLO标签文件。通过可视化脚本验证标注准确性后,提出多数据集融合训练策略以增强模型泛化能力。最后使用Ultralytics框架启动训练,展现了从环境搭建到模型训练的完整技术路径。该方案兼顾检测

Hi20240217的博客 1094

Effective C++ 读书笔记 Item28 不要返回对象内部的句柄

不要返回对象私有成员的句柄。这里的“句柄”(handle)包括引用、指针和迭代器。 这样可以增加类的封装性、使得const函数更加const, 也避免了空引用的创建(dangling handles)。 句柄就是个数字,一般和当前系统下的整数的位数一样,比如32bit系统下就是4个字节。这个数字是一个对象的唯一标示,和对象一一对应。 这个对象可以是一个块内存,一个资源,或者一个服务的contex...

Vermont_的博客 241

Windows C语言编程:Beep API实现蜂鸣器原理与实战

如果你在 Windows 上写过 C 语言程序,想给程序加个简单的提示音,第一个想到的可能是 printf("\a") 。这个转义字符确实能在某些终端里发出“嘀”的一声,但它太原始、太不可控了,而且很多时候根本没声音。那么,有没有一种更“Windows”、更可控、更专业的方法来让你的程序“说话”呢? 答案是肯定的,而且它比你想象的要强大和复杂。Windows 提供了一个名为 Beep 的 API 函数,专门用于生成蜂鸣声。你可能觉得这功能太简单,甚至有点过时——不就是让电脑“哔”一声吗?但恰恰是这个看似简单

weixin_34109408的博客 395

读书笔记 effective c++ Item 28 不要返回指向对象内部数据(internals)的句柄(handles)...

  假设你正在操作一个Rectangle类。每个矩形可以通过左上角的点和右下角的点来表示。为了保证一个Rectangle对象尽可能小,你可能决定不把定义矩形范围的点存储在Rectangle类中,而是把它放入一个辅助结构体中,Rectangle中声明一个指向它的指针就可以了: 1 class Point { // class for rep...

HarlanC的专栏 183

C#菜鸟教程学习笔记

C#菜鸟教程学习笔记 C#简介 C# 是一种编程语言,它是由微软开发的。 C# 编程是基于 C 和 C++ 编程语言的,它与 Java 也非常相似。 C# 是 .Net 框架的一部分,且用于编写 .Net 应用程序。 .Net 框架(.Net Framework)能编写出下面类型的应用程序: ①Windows 应用程序 ②Web 应用程序 ③Web 服务 常用的C# 编程的开发工具:Visual Studio(VS:可视化工作室) C#程序结构 一个 C# 程序(C# 文件的后缀为 .cs)主要包括以下部分

mlc_WTMOTW的博客 4978

ABAP调用启信宝API

方法参数定义如下 源代码如下 method qxb_http_get. data:lv_url type string. "===============初始化=============================================== "获取http实例 cl_http_client=>create_by_destination( exporting destination = space importing

u012232542的博客 1312

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

(先进后出)

xys_678的博客 254

【ArcGIS Pro微课1000例】0022:基于DEM进行流域分析生成流域图

填洼Fill,在进行水文分析后续操作前,首先要对DEM进行填洼,创建无凹陷点的DEM。在ArcGIS中使用的是八方向流量建模(D8算法),工具位于水文分析下的【流向】。填洼需要使用水文分析工具下的【填洼】。确定输入与输出即可。

智慧空间实验室 2753

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

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

Maxwell_Newton的博客 349

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

廖雪峰Python教程[完整版]

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

C++移动构造函数详解

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

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

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

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

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

fpcc的专栏 88

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

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

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

2602_95684935的博客 492

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
上一篇: [翻译] Effective C++, 3rd Edition, Item 27: 最少化 casting(强制转型)(下)
下一篇: [翻译] Effective C++, 3rd Edition, Item 29: 争取 exception-safe code(异常安全代码)(上)
fatalerror99
博客等级 码龄24年 166粉丝 20原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值