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

(一)

看下面这个例子:

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

很有可能引起下面这两个错误:

(1)他们也许会以错误的次序传递参数,如:Date d(30, 3, 1995);

(2)他们可能传递一个无效的月份或天数,如:Date d(2, 30, 1995); 许多像这类客户端错误。

解决方法:简单的外覆(wrapper types)类型来区别天数、月份、和年份,然后于Date构造函数中使用这些类型:

struct Day{
    explicit Day(int d)
        : val(d){}
    int val;
};

struct Month{
    explicit Month(int m)
        : val(m);
    int val;
};

struct Year{
    explicit Year(int y)
        : val(y);
    int val;
};

class Date
{
public:
    Date(const Month& m, const Day& d, const Year& y);
    ...
};

Date d(30, 3, 1998); //错误,不正确类型
Date d(Day(30), Month(3), Year(1998));//错误,不正确类型
Date d(Month(3), Day(30), Year(1998));//正确,正确类型

一旦正确的类型就定位,限定其值有时候是通情达理的,比较安全的做法是预先定义:

class Month {
public:
    static Month Jan() {return Month(1);}
    static Month Feb() {return Month(2);}
    static Month Mar() {return Month(3);}
    ...
    static Month Dec() {return Month(12);}
private:
    explicit Month(int m);   //阻止生成新的月份
    ...
};

所以就可以像下面这样调用了!这样的话就不能用无效的数据调用了。

Date d(Month::Mar(); Day(3), Year(1998));

(二)

预防客户错误的另一个办法是:限制类型内什么事可做,什么事不能做。常见的限制是加上const。

另一个一般性准则是:“除非有好理由,否则应该尽量令你的types的行为与内置types一致”。一旦怀疑,就拿ints做范本。

避免与内置类型不兼容,真正的理由是为了提供行为一致的接口,stl容器的接口十分一致,使得它们很容易被使用。所以尽全力提供行为一致的接口!

(三)

Investment* createInvestment();

在前面说过把这个返回的指针放入智能指针中,为了防止资源泄漏!

但是如果客户忘记用智能指针的话,那怎么办!

解决方法:很多时候,较佳接口的设计原则是先发制人,就令factory函数返回一个智能指针:

tr1::shared_ptr<Investment> createInvestment();

这便实质上强迫客户将返回值存储于一个tr1::shared_ptr内,几乎消除了忘记删除底部Investment对象(当它不再被使用时)的可能性。

(四)

如果我们要实现createInvestment使他返回一个tr1::shared_ptr并夹带getRidOfInvestment函数作为删除器:

tr1::shared_ptr<Investment> createInvestment() {
	tr1::shared_ptr<Investment> retVal(static_cast<Investment*>(0), getRidOfInvestment);
	retVla = ...;  //令retVal指向正确的对象。
	return retVal;
}

在上面的代码中,我们创建了一个初值为 null ,并且以getRidOfInvestment为删除器的tr1::shared_ptr。

当然了,如果被pInv管理的原始指针可以在建立pInv之前先确定下来,那么肯定“将原始指针传给pInv构造函数”会比“先将pInv初始化为null,再对他进行一次赋值操作”更好!

(五)

cross-Dll problem:对象在一个dll中被new,却在另一个dll内被delete。在许多平台上,这一类“跨dll的new/delete成对运用”会导致运行期错误。

解决办法:

shared_ptr没有这个问题,因为它缺省的删除器是来自“shared_ptr诞生所在的那个Dll”的delete。

例如假设Stock是派生自Investment的:

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

返回的那个tr1::shared_ptr可被传递给任何其他的DLLs,无需在意“cross-DLL problem”。因为这个指向Stock的tr1::shared_ptr会追踪记录“当Stock的引用次数变成0时该调用的那个DLL‘s delete”。所以用shared_ptr可以潜在的消除cross-Dll problem。

请记住:

(1)好的接口很容易被正确使用,不容易被误用.你应该在你的所有接口中努力达成这些性质.

(2) "促进正确使用"的办法包括接口的一致性,以及与内置类型的行为兼容.

(3)"阻止误用"的办法包括建立新类型、限制类型上的操作、束缚对象值以及消除客户的资源管理责任.

(2)tr1::shared_ptr支持定制型删除器.这可防范DLL问题,可被用来自动解除互斥锁等等.

Effective C++:条款18:让接口容易被正确使用,不易被误用,布布扣,bubuko.com

时间: 2025-01-02 03:06:38

Effective C++:条款18:让接口容易被正确使用,不易被误用的相关文章

effective c++ 条款18 make interface easy to use correctly and hard to use incorrectly

举一个容易犯错的例子 class Date { private: int month; int day; int year; public: Date(int month,int day,int year) { this->month = month; ... } } //wrong example Date date(30,3,1995);//should be 3,30 Date date(2,30,1995);//should be 3,30 使用类型可避免这个问题 class Month

Effective C++ 条款18

让接口容易被正确使用,不容易被误用 如题目,我们自己的程序接口是面向用户的,程序的目的不但是解决问题,而且要让用户容易使用,所以,必须保证我们的程序接口具有很强的鲁棒性. 怎么保证接口的鲁棒性,不同情况有不同的处理结果,作者列出了以下几个例子所对应的方法. 1.设计一个class来表示日期 class Date{ public: void Date(int month, int day, int year); -- }; 以上的构造接口很容易被用户用错 Date d(30, 3, 1995);/

Effective C++ 条款34 区分接口继承和是实现继承

1. C++对于函数成员的继承主要有三种: 只继承接口,不继承实现; 同时继承接口和实现,同时允许覆写实现; 继承接口和实现,同时不允许对实现进行覆写. 2. 对于public继承,成员函数的接口应该总是被继承(由于is-a关系的存在),其中: pure-virtual函数的目的只是为了使派生类继承函数接口; impure-virtual(虚但非纯虚)函数的目的是既允许派生类继承接口和实现,又可以重写实现. non-virtual函数的目的是令派生类继承函数的接口以及一份强制实现.(如果想要重写

effective stl 条款18:避免使用vector&lt;bool&gt;

做为一个STL容器,vector<bool>确实只有两个问题.第一,它不是一个STL容器.第二,它并不容纳bool.除此以外,就没有什么要反对的了 . 在这些要求中有这样一条:如果c是一个T类型对象的容器,且c支持operator[],那么以下代码必须能够编译:T *p = &c[0]; // 无论operator[]返回什么,// 都可以用这个地址初始化一个T*换句话说,如果你使用operator[]来得到Container<T>中的一个T对象,你可以通过取它的地址而获得

Effective C++ 条款总结

自己在看这本书的时候,回去翻看目录的时候,有些规则会被遗忘,因此做个简单的小总结供自己和其他人参考,没读过的还是要先去读一遍的 一.让自己习惯C++ 1.视C++为一个语言联邦 C++是一种包含许多特性的语言,因而不要把它视为一个单一语言.理解C++至少需要学习一下4个部分: ①C语言.C++仍以C为基础 ②objected-oriented C++.面向对象编程,类.封装.继承.多态 ③template C++.C++泛型编程.模板元编程的基础 ④STL.容器.迭代器.算法 2.尽量使用con

Effective C++ (笔记) : 条款18 -- 条款23

条款18:让接口容易被正确使用,不易被误用 在(参数)类型上客户不知道怎么使用的时候,可以导入简单的"外覆"类型来区别参数.也就是,自定义数据类型,使客户明确调用相关的类型,防止误用. 尽量让自定义类型的行为和内置类型的行为相同,因为客户会想当然的和使用内置类型一样使用自定义类型,这也就是上面说的让接口容易被正确的使用.STL容器的接口十分一致,这也是他们非常容易使用的一个原因. 任何接口如果要求客户必须记得做某些事情,那么就有着"不正确的使用"的倾向,因为客户可能

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

Item 18: Make interfaces easy to use correctly and hard to use incorrectly. "让接口容易被正确使用,不易被误用",这也是面向对象设计中的重要概念,好的接口在工程实践中尤其重要. 在使用优秀的第三方组件时,常常能够切身感受到好的接口原来可以这么方便,甚至不需记住它的名字和参数就能正确地调用. 反观自己写的API,常常会有人三番五次地问这个参数怎么设置,真是失败.人非圣贤孰能无过,只能在这种痛苦的驱动下努力的重构和

条款18:让接口容易被正确使用,不易被误用(Make interface easy to use correctly and hard to use incorrectly)

NOTE : 1.好的接口容易被正确使用,不容易被误用.应该让所有接口努力达成这些性质. 2.“促进正确使用”的办法包括接口的一致性,以及内置类型的行为兼容. 3.“阻止误用”的办法包括建立新类型/限制类型上的操作,束缚对象值,以及消除客户的资源管理责任. 4.tr1::shared_ptr 支持定制型删除器(custom deleter).这可以防范DLL问题,可以被用来自动解除互斥锁(mutexs)等等.

Effective C++——条款13(第3章)

第3章    资源管理 Resource Management 所谓资源就是,一旦用了它,将来必须还给系统.C++程序中最常使用的资源就是动态内存分配(如果分配内存从来都增归还,会导致内存泄露).其他常见的资源还有文件描述符(file descriptors),互斥锁(mutex locks),图形界面中的字型和笔刷,数据库连接,以及网络sockets.不论哪一种资源,重要的是,不再使用它时,必须将它还给系统. 条款13:    以对象管理资源 Use objects to manage res