Effective C++ 笔记 —— Item 28: Avoid returning “handles” to object internals.
2021/9/9 20:34:34
本文主要是介绍Effective C++ 笔记 —— Item 28: Avoid returning “handles” to object internals.,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
Suppose you’re working on an application involving rectangles. Each rectangle can be represented by its upper left corner and its lower right corner. To keep a Rectangle object small, you might decide that the points defining its extent shouldn‘t be stored in the Rectangle itself, but rather in an auxiliary struct that the Rectangle points to:
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 }; class Rectangle { public: // ... Point& upperLeft() const { return pData->ulhc; } Point& lowerRight() const { return pData->lrhc; } // ... };
This design will compile, but it‘s wrong. In fact, it's self-contradictory. On the one hand, upperLeft and lowerRight are declared to be const member functions, because they are designed only to offer clients a way to learn what the Rectangle’' points are, not to let clients modify the Rectangle (see Item 3). On the other hand, both functions return references to private internal data — references that callers can use to modify that internal data!
Both of the problems we've identified for those functions can be eliminated by simply applying const to their return types:
class Rectangle { public: // ... const Point& upperLeft() const { return pData->ulhc; } const Point& lowerRight() const { return pData->lrhc; } // ... };
Even so, upperLeft and lowerRight are still returning handles to an object's internals, and that can be problematic in other ways. In particular, it can lead to dangling handles: handles that refer to parts of objects that don’t exist any longer. The most common source of such disappearing objects are function return values. For example, consider a function that returns the bounding box for a GUI object in the form of a rectangle:
class GUIObject { /*...*/ }; const Rectangle // returns a rectangle by boundingBox(const GUIObject& obj); // value; see Item 3 for why return type is const
Now consider how a client might use this function:
GUIObject *pgo; // make pgo point to some GUIObject const Point *pUpperLeft = &(boundingBox(*pgo).upperLeft()); // get a ptr to the upper left point of its bounding box
The call to boundingBox will return a new, temporary Rectangle object. That object doesn’t have a name, so let's call it temp. upperLeft will then be called on temp, and that call will return a reference to an internal part of temp, in particular, to one of the Points making it up. pUpperLeft will then point to that Point object. So far, so good, but we’re not done yet, because at the end of the statement, boundingBox’s return value — temp — will be destroyed, and that will indirectly lead to the destruction of temp’s Points. That, in turn, will leave pUpperLeft pointing to an object that no longer exists; pUpperLeft will dangle by the end of the statement that created it!
This is why any function that returns a handle to an internal part of the object is dangerous. It doesn’t matter whether the handle is a pointer, a reference, or an iterator. It doesn't matter whether it’s qualified with const. It doesn't matter whether the member function returning the handle is itself const. All that matters is that a handle is being returned, because once that's being done, you run the risk that the handle will outlive the object it refers to.
Things to Remember :
- Avoid returning handles (references, pointers, or iterators) to object internals. Not returning handles increases encapsulation, helps const member functions act const, and minimizes the creation of dangling handles.
这篇关于Effective C++ 笔记 —— Item 28: Avoid returning “handles” to object internals.的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23增量更新怎么做?-icode9专业技术文章分享
- 2024-11-23压缩包加密方案有哪些?-icode9专业技术文章分享
- 2024-11-23用shell怎么写一个开机时自动同步远程仓库的代码?-icode9专业技术文章分享
- 2024-11-23webman可以同步自己的仓库吗?-icode9专业技术文章分享
- 2024-11-23在 Webman 中怎么判断是否有某命令进程正在运行?-icode9专业技术文章分享
- 2024-11-23如何重置new Swiper?-icode9专业技术文章分享
- 2024-11-23oss直传有什么好处?-icode9专业技术文章分享
- 2024-11-23如何将oss直传封装成一个组件在其他页面调用时都可以使用?-icode9专业技术文章分享
- 2024-11-23怎么使用laravel 11在代码里获取路由列表?-icode9专业技术文章分享
- 2024-11-22怎么实现ansible playbook 备份代码中命名包含时间戳功能?-icode9专业技术文章分享