More Effective C++ 读书摘要(五、技巧2)Item28 - 29

C++智能指针与类继承多态 我在做编译器项目的时候, 我们采用c++语言,但要使用多态的性质,一是用引用,二是用指针。可是引用不够灵活,指针还具有内存管理问题。所以SmartPtr是一个必然的选择,可我发现通常的SmartPtr不能够支持多态,原因是编译器只能进行一次类型转换,如SmartPtr->裸指针,但裸指针到他的基类指针不会自动转换。本篇将实现一个支持多态的智能指针,没什么技术含量,大家不要见笑。原理:既然Sma 阅读详情

Item28. 智能(smart)指针:


当你使用智能指针替代C++的内建指针(dumb pointer),你就能控制下面这些方面的指针的行为:
构造和析构(Construction and destruction)、拷贝和赋值(Copying and assignment)、解引用(Dereferencing)


大多数智能指针模板看起来都象这样:

 

(题外话:当面对异常时,让对象自己开始(constructor)和结束(destructor)日志记录比显示地调用函数可以使的程序更健壮、更容易。)

 

智能指针的构造、赋值和析构

 

如果一个智能指针拥有它所指向的对象,当它被销毁时必须负责删除这个对象。
auto_ptr模板的实现大致如下:

auto_ptr采用了更为灵活的解决方案:当auto_ptr被拷贝或赋值时,同时转移对象的所有权给新的auto_ptr。

 

注意赋值操作符在接受新对象的所有权以前必须删除原来拥有的对象。如果不这样做,原来拥有的对象将永远不会被删除。记住:除了auto_ptr对象,不会有其它人拥有auto_ptr所指向的对象。

 

因为当调用auto_ptr的拷贝构造函数时,对象的所有权被传递出去,所以通过传值方式传递auto_ptr对象是一个很糟糕的方法。即:

通过const引用传递(Pass-by-reference-to-const)才是合适的做法:

 

实现解引用操作符


注意返回类型是一个引用。如果返回对象,尽管编译器允许这么做,这也将会导致灾难性后果。必须时刻牢记:pointee不用必须指向T类型对象;它也可以指向T的派生类对象。如果在这种情况下operator*函数返回的是T类型对象而不是派生类对象的引用,你的函数实际上返回的是一个错误类型的对象!(这是一个slicing问题,参见Effective C++条款22和本书条款13)。

 

 

测试智能指针是否为空

 

为了达到这个目的,传统上采取的是转换为void* 类型:

它有一个缺点:允许灵巧指针与完全不同的类型之间进行比较:
SmartPtr<Apple> pa;
SmartPtr<Orange> po;
...

if (pa == po) ...                    // 这也能够被成功编译!
即使在SmartPtr<Apple> 和 SmartPtr<Orange>之间没有operator= 函数,也能够编译,因为灵巧指针被隐式地转换为void*指针。

 

有一种折衷之策可以提供合理的测试空值的语法形式,同时把不同类型的灵巧指针之间进行比较的可能性降到最低。这就是在智能指针类中重载operator!,当且仅当灵巧指针是一个空指针时,operator!返回true:

客户端程序如下所示:

但是这样就不正确了:
if (ptn == 0) ...                    // 仍然错误
if (ptn) ...                         // 也是错误的

仅在这种情况下会存在不同类型之间进行比较:
SmartPtr<Apple> pa;
SmartPtr<Orange> po;
...
if (!pa == !po) ...                 // 仍然能够编译

幸好程序员不会经常这样编写代码。

 

把智能指针转变成dumb指针

 

并且这个函数也消除了测试空值的问题:
if (pt == 0) ...                     // 正确, 把pt转变成
                                     // Tuple*
if (pt) ...                          // 同上
if (!pt) ...                         // 同上 (reprise)

然而,它也有类型转换函数所具有的缺点(几乎总是这样,看条款5)。它使得客户端能够很容易地直接访问dumb指针,绕过“类指针(pointer-like)”对象所提供的“智能”特性。

 

提供到dumb指针的隐式类型转换的灵巧指针类也暴露了一个非常讨厌的bug。考虑这个代码:
DBPtr<Tuple> pt = new Tuple;
...
delete pt;

这段代码应该不能被编译,pt不是指针,它是一个对象,你不能删除一个对象。只有指针才能被删除,对么?

当然对了。但是回想一下条款5:编译器使用隐式类型转换来尽可能使函数调用成功,再回想一下条款8:使用delete会调用析构函数和operator delete,两者都是函数。编译器欲使在delete语句里的两个函数成功调用,就把pt隐式转换为Tuple*,然后删除它。这样做必然会破坏你的程序。


如果pt拥有它指向的对象,对象就会被删除两次,一次在调用delete时,第二次在pt的析构函数被调用时。如果pt不拥有对象,而是其他人拥有,拥有者可以删除pt,但是如果pt指向对象的拥有者不是删除pt的人,有删除权的拥有者以后还会再次删除该对象。不论是前者还是后者都会导致一个对象被删除两次,这样做会产生不能预料的后果。

所以底线很简单:除非有一个让人非常信服的理由,否则绝对不要提供转换到dumb指针的隐式类型转换操作符。

 

智能指针和继承类到基类的类型转换

这个函数能够这样使用:
Cassette *funMusic = new Cassette("Alapalooza");
CD *nightmareMusic = new CD("Disco Hits of the 70s");

displayAndPlay(funMusic, 10);
displayAndPlay(nightmareMusic, 0);

这并没有什么值得惊讶的东西,但是当我们用智能指针替代dumb指针,会发生什么呢:

void displayAndPlay(const SmartPtr<MusicProduct>& pmp,
                    int numTimes);

SmartPtr<Cassette> funMusic(new Cassette("Alapalooza"));
SmartPtr<CD> nightmareMusic(new CD("Disco Hits of the 70s"));

displayAndPlay(funMusic, 10);         // 错误!
displayAndPlay(nightmareMusic, 0);    // 错误!


幸运的是,有办法避开这种限制,这种方法的核心思想(不是实际操作)很简单:对于可以进行隐式转换的每个智能指针类都提供一个隐式类型转换操作符。但这种方法有两个缺点。第一,你必须手工特化(specialize)SmartPtr类,但是这种做法在很大程度上也就破坏了模板的通用性。第二,你可能需要添加许多类型转换符,因为你指向的对象可以位于继承层次中很深的位置,你必须为直接或间接继承的每一个基类提供一个类型转换符。

 

所幸C++最近的语言扩展,让我们能够做到这一点,这个扩展能声明(非虚)成员函数模板(通常就叫成员模板(member template)),你能使用它来生成智能指针类型转换函数,如下:

假设编译器有一个指向T对象的智能指针,它要把这个对象转换成指向“T的基类”的智能指针。编译器首先检查SmartPtr<T>类的定义,看其有没有声明相应的类型转换符,结果它没有声明。(这不意味着在上面的模板没有声明类型转换符)编译器然后检查是否存在一个成员函数模板,可以被实例化,用来进行它所期望的类型转换。它发现了一个这样的模板(带有形式类型参数newType),所以它把newType绑定到T的基类类型上,来实例化模板。

 

这种方法可以成功地用于任何合法的指针类型转换。如果你有dumb指针T1*和另一种dumb指针T2*,当且仅当你能隐式地把T1*转换为T2*时,你就能够隐式地把指向T1的智能指针类型转换为指向T2的智能指针类型。

 

但是:如何能够让智能指针在基于继承的类型转换时的行为与dumb指针一样呢?答案很简单:不可能。正如Daniel Edelson所说,智能指针固然灵巧,但不是指针。最好的方法是使用成员模板生成类型转换函数,在会产生二义性结果的地方使用casts。

 

智能指针和const

 

可以建立const和non-const对象和指针的四种不同组合:
SmartPtr<CD> p;                          // non-const 对象
                                                    // non-const 指针
SmartPtr<const CD> p;                    // const 对象,
                                                        // non-const 指针
const SmartPtr<CD> p = &goodCD;          // non-const 对象
                                                                // const指针
const SmartPtr<const CD> p = &goodCD;    // const 对象
                                                                    // const 指针

但是美中不足的是,如下代码:
CD *pCD = new CD("Famous Movie Themes");
const CD * pConstCD = pCD;
              
在dumb指针身上都是正确的,但是如果我们试图把这种方法用在灵巧指针上,情况立刻变了:
SmartPtr<CD> pCD = new CD("Famous Movie Themes");
SmartPtr<const CD> pConstCD = pCD;       // 正确么?

因为SmartPtr<CD> 与SmartPtr<const CD>是完全不同的类型。在编译器看来,它们是毫不相关的,所以没有理由相信它们是赋值兼容的。


如果你使用的编译器支持成员模板,就可以利用前面所说的技巧自动生成你需要的隐式类型转换操作。

Item29. 引用计数:


这个技巧有两个常用动机。第一个是简化跟踪堆中的对象的过程。第二个动机是由于一个简单的常识。如果很多对象有相同的值,将这个值存储多次是很无聊的。

 

实现引用计数

 

基本设计是这样的:

嵌套在String类的私有区内的StringValue类来保存引用计数及其跟踪的值,它唯一的用处就是帮助我们实现String类。
下面是StringValue的实现:

StringValue一没有拷贝构造函数和赋值运算;二没有提供对refCount的操作。不过少掉的功能将由String类提供。StringValue的主要目的是提供一个空间将一个特定的值和共享此值的String对象的数目联系起来。StringValue给了我们这个,这就足够了。


以下是String类的拷贝构造函数:

以下是String类的析构函数:

以下是赋值运算符:

 

写时拷贝(Copy-on-Write)


考虑一下数组下标操作[],它允许字符串中的单个字符被读或写:

这个函数的const版本的实现很容易,因为它是一个只读操作,String对象的值不受影响:

非const的operator[]版本就是另一回事了。它可能是被用来读一个字符,也可能用来写一个字符。不幸的是,C++编译器没有办法告诉我们一个特定的operator[]是用作读的还是写的,所以我们必须保守地假设“所有”调用非const operator[]的行为都是为了写操作。(Proxy类可以帮助我们区分读还是写,见Item30)

写时拷贝是延时求值(lazy evaluation)的一个特例,而延时求值是提高效率的一个更宽泛方法。

 


指针、引用与定时拷贝

 

大部分情况下,写时拷贝可以同时保证效率和正确性。只有一个挥之不去的问题。看一下这样的代码:
String s1 = "Hello";
char *p = &s1[1];

现在看增加一条语句:
String s2 = s1;
下面这样的语句将有一个讨厌的BUG:
*p = 'x';                     // modifies both s1 and s2!
解决方案是:在每个StringValue对象中增加一个标志以指出它是否可共享。

拷贝构造函数的实现:

非const的operator[]版本是唯一将共享标志设为false的地方:

如果使用Item30中的proxy类的技巧以区分operator[]读写操作,你通常可以降低必须被设为不可共享的StringValue对象的数目。

 

用于引用计数的基类

 

引用计数不只适用于字符串,只要是多个对象具有相同值的类理论上说都可以使用引用计数。

 

第一步是构建一个基类RCObject,任何需要引用计数的类都必须从它继承。RCObject封装了引用计数功能,以及增加和减少引用计数的函数。它还包含了当这个值不再被用到时(也就是引用计数为0时)销毁对象的代码。最后,它包含了一个字段以跟踪这个值对象是否可共享,并提供查询这个值和将它设为false的函数。不需将可共享标志设为true的函数,因为所有的值对象默认都是可共享的。一旦一个对象变成了不可共享,将没有办法使它再次成为可共享。

 

RCObject的定义如下:

注意这里的虚析构函数,它明确表明这个类是被设计了作基类使用的。同时要注意这个析构函数是纯虚的,它明确表明这个类只能作基类使用。


RCOject的实现代码:

在两个构造函数中都将refCount设成了0。实际上REObjects的创建者会把refCount设为1。

另外拷贝构造函数也将refCount设成了0,而不管被拷贝的RCObject对象的refCount的值。这是因为我们正在创建新对象以代表这个值,而这个新的对象总是未被共享的,并且只被它的创建者引用。

!!!注意,创建者将必须负责将refCount设为正确的值。

 

RCObject的赋值运算看起来完全是颠覆性的:它不做任何事情。

 

为了使用新写的引用计数基类,将StringValue修改为从RCObject继承而得到引用计数功能:

这个版本的StringValue和前面的几乎一样,唯一改变的就是StringValue的成员函数不再处理refCount字段。RCObject现在接管了这个工作。

 

引用计数操作的自动化

 

供引用计数对象使用的智能指针模板:

这个模板可以让智能指针对象控制在构造、赋值、析构时控制所发生的事情。
它有两个构造函数:

因为init()中的pointee = new T(*pointee)会创建一个新的T对象,并用拷贝构造函数进行了初始化。所以我们必须在StringValue中增加这样的一个构造函数:

RCPtr<T>不仅仅假设T类型有深拷贝的构造函数,它还要求T从RCObject继承,或至少提供了RCObject的所提供的函数。

 

RCPtr<T>的最后一个假设是它所指向的对象类型为T。这似乎是显然的。毕竟pointee的类型被申明为T*。但pointee可能实际上指向T的一个派生类。我们可以提供使用虚拷贝构造函数(见Item25)来实现这一点。

 

用这种方式实现了RCPtr的构造函数后,类的其它函数实现得很轻快。赋值运算很简洁明了:

析构函数很容易。当一个RCPtr被销毁时,它只是简单地将它对引用计数对象的引用移除:

最后,RCPtr的模拟指针的操作就是在Item28中看到的智能指针的部分:

 

合在一起

 

终于可以这些零散的代码放在一起,使用可重用的RCObject和RCPtr类构建带引用计数的String类。

 

类的定义是:

这里有一个重大的不同:这个String类的公有接口和本条款开始处我们使用的版本不同。拷贝构造函数在哪里?赋值运算在哪里?析构函数在哪里?这儿明显有问题。实际上,没问题。它工作得很好。如果你没看出为什么,prepare yourself for a C++ epiphany。

 

String对象仍然可以被拷贝,并且,这个拷贝可以正确处理后台被引用计数的StringValue对象,但String类不需要写下哪怕一行代码。因为编译器为String自动生成的拷贝构造函数将自动调用其RCPtr成员的拷贝构造函数,而这个拷贝构造函数完成所有的对StringValue对象的必要操作,包括它的引用计数。RCPtr是一个智能指针,所以这是它的本职工作。它同样处理赋值和析构,所以String类同样不需要写出这些函数。

 

下面是RCObject的实现:

下面是RCPtr的实现:

下面是String::StringValue的实现:

最后是String,它的实现是:

 

为既有类添加引用计数

 

到现在为止,我们所讨论的都假设我们能够访问有关类的源码。但如果我们想让一个位于不能被修改的程序库中的类获得引用计数的好处呢?


可以套用这句格言:计算机科学中的绝大部分问题都可以通过增加一个中间层次来解决。

 

增加一个新类CountHolder以处理引用计数,它从RCObject继承。我们让CountHolder包含一个指针指向Widget。然后用等价的智能指针RCIPter模板替代RCPtr模板,它知道CountHolder类的存在。(名字中的“i”表示间接“indirect”。)

 

RCIPtr的实现如下:

RCIPtr与RCPtr只两处不同。第一,RCPtr对象直接指向值对象,而RCIptr对象通过中间层的CountHolder对象指向值对象。第二,RCIPtr重载了operator->和operator*,当有对被指向的对象的非const的操作时,写时拷贝自动被执行。

 

有了RCIPtr,很容易实现RCWidget,因为RCWidget的每个函数都是将调用传递给RCIPtr以操作Widget对象。举个例子,如果Widget是这样的:

那么RCWidget将被定义为这样:

注意RCWidget的构造函数是怎么用它被传入的参数调用Widget的构造函数的;RCWidget的doThis怎么调用Widget的doThis函数的;以及RCWidget的showThat怎么返回Widget的showThat的返回值的。同样要注意RCWidget没有申明拷贝构造函数和赋值操作函数,也没有析构函数。

 

小结:引用计数通常假设对象共享相同的值。如果假设不成立的话,引用计数将比通常的方法使用更多的内存和执行更多的代码。另一方面,如果你的对象确实有具体相同值的趋势,那么引用计数将同时节省时间和空间。

 

总之,引用计数在下列情况下对提高效率很有用:
①少量的值被大量的对象共享。这样的共享通常通过调用赋值操作和拷贝构造而发生。对象/值的比例越高,越是适宜使用引用计数。
②对象的值的创建和销毁代价很高昂,或它们占用大量的内存。即使这样,如果不是多个对象共享相同的值,引用计数仍然帮不了你任何东西。

 

使用profiler或其它工具来分析才能确认这些条件是否满足。

 

即使上面的条件满足了,使用引用计数仍然可能是不合适的。有些数据结构(如有向图)将导致自我引用或环状结构。这样的数据结构可能导致孤立的自引用对象,它没有被别人使用,而其引用计数又绝不会降到零。因为这个不被外部对象用到的结构中的每个对象都被该结构内部的至少一个对象所引用。

 

让我们用最后一个问题结束讨论。当RCObject::removeReference减少对象的引用计数时,它检查新值是否为0。如果是,removeReference通过调用delete this销毁对象。这个操作只在对象是通过调用new生成的时才安全,所以我们需要一些方法以确保RCObject只能用这种方法产生。


此处,我们用约定的方法来解决。RCObject被设计为只作被引用计数的值对象的基类使用,而这些值对象应该只通过智能指针RCPtr引用。此外,值对象应该只能由值会共享的对象来实例化;它们不能被按通常的方法使用。

 

于是,我们可以指定一组满足这个要求的类,并确保只有这些类能创建RCObject对象,从而限制RCObject只能在堆上创建。

基于STM32的RS485土壤氮磷钾与PH传感器数据采集与OLED显示实战(附完整代码) 本文详细介绍了基于STM32单片机通过RS485协议采集土壤氮磷钾与PH传感器数据的实战项目。涵盖硬件选型、连接方法、Modbus-RTU通信协议解析、STM32程序实现及OLED显示,提供完整代码和调试技巧,适用于农业物联网环境监测系统。 阅读详情

相关推荐

解密电商大促背后的智慧:LSTM与ARIMA模型的双剑合璧

举个例子,如果某东发现某款新推出的电子产品在促销前夕搜索量突然暴涨,虽然这个产品没有过去的销售记录,但LSTM模型可以结合用户对类似产品的行为模式、实时的市场反馈,迅速捕捉到这些变化,并预测这款产品在大促期间的需求会急剧上升。想象一下,如果预测不准确,备货不足,商品很快就卖光了,大量用户可能在促销期间买不到想要的商品,这不仅让用户失望,还会影响某东的品牌形象。这种情况就像我们看一部很长的电视剧,看得越久,前面的情节可能就越来越模糊,到最后有些关键的情节细节都忘了,影响了对整个剧情的理解。

小蒋聊技术 2091

C++11智能指针shared_ptr应用于继承结构

在进行向上转换时,dynamic_cast和static_cast一样,dynamic_pointer_cast和static_pointer_cast一样。但进行向下转换时,dynamic_cast和static_cast不一样,dynamic_pointer_cast和static_pointer_cast也不一样。同样的,我们也可以用支持RTTI的dynamic_pointer_cast对智能指针进行向下转换。我们用支持RTTI的dynamic_cast对裸指针进行向下转换。

长期更新自学笔记 1344

SAP中贸易伙伴的应用原理简析

公司也称为贸易伙伴,是出具合并报表的组织单位,可以为客户和供应商分配公司(贸易伙伴),用于识别集团内关闻公司间的业务往来,在编制合并报表时进行往来账务的计算处理。 如下图某贸易伙伴公司(关联方名称G0059)在我方公司的SAP系统中有多重身份(即是供应商,又是客户)。那么在我方公司SAP系统中建立起公司(贸易伙伴),并关联到供应商和客户主数据中。之后,就可以通过G0059这个贸易伙伴名称来识别与该贸易伙伴间的往来业务。 相应的配置设定如下: 定义公司(贸易伙伴或关联方) 会计凭证中会

专注SAP应用技术文章写作,致力于拉近用户与系统间的距离; 9817

智能指针_继承多态

自主的内存回收机制:1、手动开辟 2、系统释放 栈上的内存:1、系统开辟 2、系统释放 堆上的内存:1、手动开辟 2、手动释放 对象的生存:1、开辟内存 2、调用构造函数 对象的销毁:1、调用析构函数 2、释放内存 int *p=new int 堆上开辟内存,把操作的所有权限交给栈上的变量,栈上的内存系统释放,而堆上的内存需要手动释放 可以把权限...

Dthinking的博客 794

扩展卡尔曼滤波(EKF)理论讲解与实例(matlab、python和C++代码)

扩展卡尔曼滤波(EKF)理论讲解与实例(matlab、python和C++代码) 文章目录扩展卡尔曼滤波(EKF)理论讲解与实例(matlab、python和C++代码)理论讲解KF和EKF模型对比雅可比矩阵计算计算实例应用实例线性模型CV模型:CA模型非线性模型CTRV模型:CTRV实例(python)small demo抛物线demo飞机高度demoC++实例参考文献 我们上篇提到的卡尔曼滤波是用于线性系统,预测(运动)模型和观测模型是在假设高斯和线性情况下进行的。简单的卡尔曼滤波必须应用在符合高斯分布

O_MMMM_O的博客 10万+

DCM、PLL以及DLL等概念及详情

介绍DLL、PLL以及DCM的概念,总结其模块构成、工作原理、相互之间的差异与各自优势。

CLL_caicai的博客 8339

45.继承的方式

派生类访问控制 派生类继承基类,派生类拥有基类中全部成员变量和成员方法(除了构造和析构之外的成员方法),但是在派生类中,继承的成员并不一定能直接访问 继承方式 不管公有继承 保护 还是私有 基类中的私有属性 ,都不可以继承下去 公有继承 父类中的protected 在子类中是 protected 父类中的public 在子类中是 public 保护继承 父类中...

augfun的博客 154

最新,弱小目标检测数据集,持续更新中。

梳理了最新的下弱小目标检测数据库,方便后续开发使用

weixin_43331421的博客 4100

C++虚函数、虚继承、虚基类、多态、智能指针

1,什么是虚函数 2,虚继承在什么情况下使用 子类继承来自于同一个公共祖先的多个父类的时候?

Hello Word! 856

SAP_MM模块采购价格确定控制简介

SAP MM模块采购价格确定控制是采购管理中的关键功能,系统通过"价格确定日期"判断条件记录有效性并带出正确价格。文章分析了四种常见业务场景及其对应的价格确定方案:普通采购订单(创建日期)、长期合同(交货日期)、特殊业务(手动输入)和接口下单(系统传入)。详细介绍了配置方法和前台操作步骤,并提供了不同业务类型对应的推荐控制方式汇总表。通过合理设置价格确定日期控制,企业可以确保采购价格准确性,满足各种复杂业务场景下价格管理的需求,从而提高采购管理效率和成本控制能力。

我小时候很黑的博客 738

硬件知识点-----SPI串联电阻、振铃、过冲

电阻取值,没有公式,一被传输线的特征阻抗为50欧姆左右,而TTL电路输出电阻大桃为13欧姆左右,在源端串一个33姆,大致和50相当,这样就可以柳制从终端反射回来的倍号,防止再次反射。传输时间tp=L/V,其中L是导线长度,V是电磁波在电路板中的传输速度V=C/sqrDk,其中Dk是光速衰减因子,对于电路板而言是铜线,Dk=4电磁波在电路板中的速度都是慢于光速的。实际上串联多大的电阻与传输线的阻抗有关,为了保证阻抗的连续性,如果传输线的特性阻抗 Z0与驱动源的输出阻抗 Zd不匹配,会引发信号的反射。

贾saisai的博客 2722

More Effective C++ 读书摘要(五、技巧3)Item30 - 31

Item30. 代理类: 实现二维数组 对于C++内置的数组,如data[][],第一个[]返回的是一个数组,第二个[]从这个返回的数组中再去取一个元素。我们可以通过重载Array2D类的operator[]来玩同样的把戏。Array2D的operator[]返回一个新类Array1D(代表一维数组)的对象,再重载Array1D的operator[]来返回所需要的二维数组中的元

thy专栏 1034

FLUENT 软件中design modeler网格划分后,导出失败:系统显示“在网格文件导出过程中出现异常。请将数据发送给您的技术支持供应商。”...如何解决?

🏆 本文收录于《全栈Bug调优(实战版)》专栏,致力于分享我在项目实战过程中遇到的各类Bug及其原因,并提供切实有效的解决方案。无论你是初学者还是经验丰富的开发者,本文将为你指引出一条更高效的Bug修复之路,助你早日登顶,迈向财富自由的梦想🚀!同时,欢迎大家关注、收藏、订阅本专栏,更多精彩内容正在持续更新中。让我们一起进步,Up!Up!Up!    备注: 部分问题/难题源自互联网,经过精心筛选和整理,结合数位十多年大厂实战经验资深大佬经验总结所得,数条可行方案供所需之人参考。

**My Coding Family** 1474

More Effective C++ 读书摘要(五、技巧1)Item25 - 27

 Item25. 使构造函数和非成员函数具有虚函数的行为:有三个类,注意其继承关系:class NLComponent { //用于 newsletter components public: // 的抽象基类 ... //包含只少一个纯虚函数}

thy专栏 1077

android 蓝牙通讯demo

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

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

More Effective C++ 读书摘要(三、异常)Item9 - 15

为什么一定要使用异常?答案很简单:异常不能被忽略。Item9.使用析构函数防止资源泄漏:通过智能指针auto_prt将清除代码放入其析构函数里。核心部分如下:templateclass auto_ptr {public: auto_ptr(T *p=0): ptr(p) {} ~auto_ptr() {delete ptr;} private:

thy专栏 915

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

Effective C++ 读书笔记 Item1-Item4

目录 守则01:把C++看做一个语言的集合,而不是单一的语言 守则02:尽量使用const, enum, inline, 减少宏变量#define的使用 守则03: 尽可能使用const关键字 守则04: 在使用前保证对象是初始化的 看完C++ Primer,最近吃了安利开始啃Scott Meyers的Effective C++第三版,书中干货不少,非常值得深思借鉴。但是也有点太多了(→...

Vermont_的博客 416

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

More Effective C++ 读书摘要(六、杂项)Item32 - 35

Item32. 在将来时态下开发程序: 作为软件开发人员,我们也许知道得不够多,但我们知道万物都会变化。我们没必要知道什么将发生变化,这么变化又怎么发生,以什么时候发生,在哪里发生,但我们知道:万物总会变化。 好的软件能够适应变化。它提供新的特性,适应到新的平台,满足新的需求,处理新的输入。这种软件的灵活性、健壮性、可靠性不是来自于运气。它是那些遵照了现在的要求并关注了将来可能的开

thy专栏 914

读书笔记 effective c++ Item 12 拷贝对象的所有部分

正文 回到顶部 1.默认构造函数介绍 在设计良好的面向对象系统中,会将对象的内部进行封装,只有两个函数可以拷贝对象:拷贝构造函数和拷贝赋值运算符。我们把这两个函数统一叫做拷贝函数。从Item5中,我们得知,如果需要的话编译器会为你生成这两个拷贝函数,并且编译器生成的版本能够精确的做到你想做的:它们拷贝了对象的所有数据。 回到顶部 2.自己实现构造函数有可能出现问题 

tmchongye的专栏 3383

Effective C++ 读书笔记 Item29 追求异常安全的代码

考虑下面例子,有一个菜单类, changeBg 函数可以改变它的背景,切换背景计数,同时提供线程安全: class Menu{ Mutex mutex; //提供多线程互斥访问 Image *bg; //背景图片 int changeCount; //切换背景计数 public : void changeBg(istream& sr); }; ...

Vermont_的博客 261

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

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

Vermont_的博客 241

Effective C++学习笔记(Part Five:Item 26-31)

最近终于把effectvie C++仔细的阅读了一边,很惊叹C++的威力与魅力。最近会把最近的读书心得与读书笔记记于此,必备查找使用,如果总结有什么不 当之处,欢迎批评指正: 现在只列出框架,最近会尽快填充完整: 第5部分:实现(Implementations) 本部分主要讲述了类实现过程中的一些原则,为设计出高效率的实现方式,这是你的必经之路;在这一部分读的比较仔

海将军 531

《Effective C++》读书笔记之item29:为“异常安全”而努力是值得的

1.“异常安全性”(exception safety)能够为函数带来两个好处: 不泄漏任何资源;不允许数据败坏:操作未正确完成却已经改变了部分数据。 以这样的思想设计的函数(异常安全性函数)提供以下三个保证,即具有三个安全性等级: 基本承诺:如果抛出异常,程序内的任何事物仍然保持在有效状态下,没有任何对象或数据结构会因此而败坏,所有对象都处于一种内部前后一致的状态。但程序的现实状态不

banguijun的专栏 870

More Effective C++:Item 1-Item 8读书笔记

Item M1:指针与引用的区别 在以下情况下你应该使用指针,一是你考虑到存在不指向任何对象的可能(在这种情况下,你能够设置指针为空),二是你需要能够在不同的时刻指向不同的对象(在这种情况下,你能改变指针的指向 Item M2:尽量使用C++风格的类型转换 static_cast在功能上基本上与C风格的类型转换一样强大,含义也一样; const_cast用于类型转换掉表达式的const...

部落阁 407

读书笔记 effective c++ Item 30 理解内联的里里外外 (大师入场啦)

正文 最近北京房价蹭蹭猛涨,买了房子的人心花怒放,没买的人心惊肉跳,咬牙切齿,楼主作为北漂无房一族,着实又亚历山大了一把,这些天晚上睡觉总是很难入睡,即使入睡,也是浮梦连篇,即使亚历山大,对C++的热情和追求还是不减,应该是感动了周公吧,梦境从此处开始,大师入场来给我安慰了。。。 11点躺在床上了,脑子里总结一下最近的工作:最近的开发用到inline函数比较多,众所周知,inline的

tmchongye的专栏 2166

More Effective C++ 读书摘要(一、基础议题 二、运算符)Item1 - 8

〇、“引言”约定与术语:1.指针加p,引用加r。2.(在对operator==)的调用中,lhs和rhs,分别为“left-hand side”、“right-hand side”的缩写。3.ctor表示“constructor”,dtor表示“destructor” 一、基础议题Item 1. 区分指针和引用:以下情况应该使用引用->①当知道要指代某个对象并且不会再指代其他的东西②当实现

thy专栏 820

读书笔记 effective c++ Item 13 用对象来管理资源

正文 回到顶部 1.不要手动释放从函数返回的堆资源 假设你正在处理一个模拟Investment的程序库,不同的Investmetn类型从Investment基类继承而来, 1 class Investment { ... }; // root class of hierarchy of 2 3 // investment types 进一步假设这个程序库通过一个工厂函数(I

tmchongye的专栏 3099
上一篇: 《Beginning Python From Novice to Professional》学习笔记八:Abstraction
下一篇: 《Beginning Python From Novice to Professional》学习笔记九:More Abstraction
thy38
博客等级 码龄19年 184粉丝 116原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值