Effective c++条款28

举个例子:

复制代码
 1 class Student
 2 {
 3 private:
 4     int ID;
 5     string name;
 6 public:
 7     string& GetName()
 8     {
 9         return name;
10     }
11 };
复制代码

这是一个学生的类,类里面有两个成员变量,一个是学生ID,用整数表示,另一个是姓名,用string表示。有一个公有的方法GetName(),获得学生的名字,根据条款20所说的,使用引用可以防止资源不必要地拷贝,那么在返回值这边就用string&。但现在问题来了,这个函数只是想返回学生的姓名,并不想用户对之进行修改,但返回引用却提供了这样的一个接口,如:

复制代码
int main()
{
    Student s;
    s.GetName() = "Jerry";
    cout << s.GetName() << endl;
}
复制代码

就可以把名字进行修改。

你也许想到了,如果在前面加上const,像这样:

1 const string& GetName()
2 {
3     return name;
4 }

就可以阻止s.GetName() = “Jerry”这样的代码了。

但这样写还是存在问题,就是如果返回的引用生命周期比对象本身要长时,引用就会悬空,它会指向一个不存在的string。下面看一下“返回的引用生命周期比对象本身要长”的情况,这种情况还是很容易举出例子的,比如:

复制代码
1 const string& fun()
2 {
3     return Student().GetName();
4 }
5 
6 int main()
7 {
8     string name = fun(); //name指向一个不存的对象的成员变量
9 }
复制代码

这时候即使name读取不报错,也是一个巨大的隐患,因为它已经是虚吊(dangling)的了。

这就是为什么函数如果“返回一个handle代表对象内部成分”总是危险的原因,不在于返回值是不是const,而是在于如果handle(指针或引用)传出去了,就会暴露在“handle比其所指对象更长寿”的风险下。

但有些情况还是需要返回handle的,比如string或者vector里面的operator[],就是返回的引用,因为需要对这里面的元素进行操作。

好了,总结一下:

避免返回handles(包括reference、指针、迭代器)指向对象内部,遵守这个条款可增加封装性,并将发生dangling handles的可能性降至最低。如果有必要必须要返回handles,在编写代码时就一定要注意对象和传出handle的生命周期。

发布了12 篇原创文章 · 获赞 6 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/huaweizte123/article/details/54561376
今日推荐