`
kmplayer
  • 浏览: 508825 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

条款29:避免传回内部数据的handles

 
阅读更多
1,考虑下面的代码:
class string
{
operator char*() const;
...
}

const String B("Hello World");
char* str = B;//调用B.operator char*()
strcpy(str, "Hi Tom");

3,一个快速但是不正确的实现:
inline String::operator char*() const
{
    return data;
}
注:这个handler给了调用者无限制使用"私有字段data所指目标之物"的权利.
如下图所示:



实例代码:
#include <iostream>
#include <string.h>

using namespace std;

class String
{
public:
    String(const char* value);
    String(const String& rhs);
    ~String();
    String& operator=(const String& rhs);
    friend ostream& operator << (ostream& out, const String str);
    operator char*() const;
private:
    char* data;
};

inline String::String(const char* value)
{
    if (value)
    {
        data = new char[strlen(value)+1];
        strcpy(data, value);
    }
    else
    {
        data = new char[1];
        *data = '\0';
    }
}

inline String::String(const String& rhs)
{
    //这里data第一次被分配空间
    data = new char[strlen(rhs.data)+1];
    strcpy(data, rhs.data);
}

inline String::~String()
{
    delete[] data;
}

inline String& String::operator=(const String& rhs)
{
    if (this == &rhs)
        return *this;
    delete[] data;
    data = new char[strlen(rhs.data)+1];
    strcpy(data, rhs.data);
    return *this;
}

ostream& operator << (ostream& out, const String str)
{
    return out << str.data;
}

//这里应该避免,传回内部数据的handler,内部数据可能会被修改

inline String::operator char*() const
{
    return data;
}

int main()
{
    const String B("Hello World");
    cout << B << endl;
    char* str = B;//调用B.operator char*()
    strcpy(str, "Hi Tom");
    cout << B <<endl; //私有数据被改变了
    return 0;
}

4,一个比较慢但是比较安全的做法:
inline String::operator char*() const
{
char* copy = new char[strlen(data)+1];
strcpy(copy, data);
    return copy;
}
注:代价,函数调用者必须记得将获得的指针delete.

实例代码:
#include <iostream>
#include <string.h>

using namespace std;

class String
{
public:
    String(const char* value);
    String(const String& rhs);
    ~String();
    String& operator=(const String& rhs);
    friend ostream& operator << (ostream& out, const String str);
    operator char*() const;
private:
    char* data;
};

inline String::String(const char* value)
{
    if (value)
    {
        data = new char[strlen(value)+1];
        strcpy(data, value);
    }
    else
    {
        data = new char[1];
        *data = '\0';
    }
}

inline String::String(const String& rhs)
{
    //这里data第一次被分配空间
    data = new char[strlen(rhs.data)+1];
    strcpy(data, rhs.data);
}

inline String::~String()
{
    delete[] data;
}

inline String& String::operator=(const String& rhs)
{
    if (this == &rhs)
        return *this;
    delete[] data;
    data = new char[strlen(rhs.data)+1];
    strcpy(data, rhs.data);
    return *this;
}

ostream& operator << (ostream& out, const String str)
{
    return out << str.data;
}

//一种比较慢的版本,但是要手工delete.
inline String::operator char*() const
{
	char* copy = new char[strlen(data)+1];
	strcpy(copy, data);
    return copy;
}

int main()
{
    const String B("Hello World");
    cout << B << endl;
    char* str = B;//调用B.operator char*()
    strcpy(str, "Hi Tom");
    cout << B <<endl;
    delete str;
    return 0;
}

5,另一个稍有不同的策略:传回一个指向const char的指针.
inline String::operator const char*() const
{
return data;
}
实例代码:
#include <iostream>
#include <string.h>

using namespace std;

class String
{
public:
    String(const char* value);
    String(const String& rhs);
    ~String();
    String& operator=(const String& rhs);
    friend ostream& operator << (ostream& out, const String str);
    operator const char*() const;
private:
    char* data;
};

inline String::String(const char* value)
{
    if (value)
    {
        data = new char[strlen(value)+1];
        strcpy(data, value);
    }
    else
    {
        data = new char[1];
        *data = '\0';
    }
}

inline String::String(const String& rhs)
{
    //这里data第一次被分配空间
    data = new char[strlen(rhs.data)+1];
    strcpy(data, rhs.data);
}

inline String::~String()
{
    delete[] data;
}

inline String& String::operator=(const String& rhs)
{
    if (this == &rhs)
        return *this;
    delete[] data;
    data = new char[strlen(rhs.data)+1];
    strcpy(data, rhs.data);
    return *this;
}

ostream& operator << (ostream& out, const String str)
{
    return out << str.data;
}

//这里应该避免,传回内部数据的handler,内部数据可能会被修改

inline String::operator const char*() const
{
    return data;
}

int main()
{
    const String B("Hello World");
    cout << B << endl;
    const char* str = B;//调用B.operator const char*()
    strcpy(str, "Hi Tom"); //显式说明,不能改变
    return 0;
}

6,指针并不是"传回内部资料之handler"的唯一途径.
考虑下面的代码:
#include <iostream>
#include <string.h>

using namespace std;

class String
{
public:
    String(const char* value);
    String(const String& rhs);
    ~String();
    String& operator=(const String& rhs);
    friend ostream& operator << (ostream& out, const String str);
    operator const char*() const;
    char& operator[](int index) const { return data[index]; }
private:
    char* data;
};

inline String::String(const char* value)
{
    if (value)
    {
        data = new char[strlen(value)+1];
        strcpy(data, value);
    }
    else
    {
        data = new char[1];
        *data = '\0';
    }
}

inline String::String(const String& rhs)
{
    //这里data第一次被分配空间
    data = new char[strlen(rhs.data)+1];
    strcpy(data, rhs.data);
}

inline String::~String()
{
    delete[] data;
}

inline String& String::operator=(const String& rhs)
{
    if (this == &rhs)
        return *this;
    delete[] data;
    data = new char[strlen(rhs.data)+1];
    strcpy(data, rhs.data);
    return *this;
}

ostream& operator << (ostream& out, const String str)
{
    return out << str.data;
}

//这里应该避免,传回内部数据的handler,内部数据可能会被修改

inline String::operator const char*() const
{
    return data;
}

int main()
{
    String s = "I'm not constant";
    s[0] = 'x';
    cout << s << endl;
    const String cs = "I'm constant";
    cs[0] = 'x';
    cout << cs << endl; //这里const对象指向的数据被改变了
    return 0;
}

解决之道:
(1)让函数成为non-const;
(2)重写函数,不要让它传回任何handle.

7,即使是non-const member functions,也必须面对这个事实:handle的有效性将在它所对应的那个对象终了时结束.
考虑下面的代码:
#include <iostream>
#include <string.h>

using namespace std;

class String
{
public:
    String(const char* value);
    String(const String& rhs);
    ~String();
    String& operator=(const String& rhs);
    friend ostream& operator << (ostream& out, const String str);
    operator const char*() const;
    char& operator[](int index) const { return data[index]; }
private:
    char* data;
};

inline String::String(const char* value)
{
    if (value)
    {
        data = new char[strlen(value)+1];
        strcpy(data, value);
    }
    else
    {
        data = new char[1];
        *data = '\0';
    }
}

inline String::String(const String& rhs)
{
    //这里data第一次被分配空间
    data = new char[strlen(rhs.data)+1];
    strcpy(data, rhs.data);
}

inline String::~String()
{
    delete[] data;
}

inline String& String::operator=(const String& rhs)
{
    if (this == &rhs)
        return *this;
    delete[] data;
    data = new char[strlen(rhs.data)+1];
    strcpy(data, rhs.data);
    return *this;
}

ostream& operator << (ostream& out, const String str)
{
    return out << str.data;
}

//这里应该避免,传回内部数据的handler,内部数据可能会被修改

inline String::operator const char*() const
{
    return data;
}

String someFamousAuthor()
{
    return "Stephen King";
}

int main()
{
    cout << someFamousAuthor() << endl;
    const char* pc = someFamousAuthor();
    cout << pc << endl; //pc指向的区域已经被delete.
    return 0;
}

发生的事情:
(1)产生一个暂时性的String object,用来放置someFamousAuthor()传回值.
(2)经由operator const char* member function,上述暂时对象被转换为一个cosnt char*,pc设置为data指针.
(3)暂时性String对象被销毁时,它的destructor被调用,它的data指针被删除,此时pc指向一块被删除过的地方.

8,总结:const member functions传回handles是不好的行为,甚至对non-const member functions而言,传回handles也会导致麻烦,特别是设计暂时性对象时.
  • 大小: 24 KB
分享到:
评论

相关推荐

    Effective C++(第三版)

    条款28:避免返回handles指向对象内部成分 avoid returning “handles” to object internals. 条款29:为“异常安全”而努力是值得的 strive for exception-safe code. 条款30:透彻了解inlining的里里外外 ...

    Effective C++ 中文版

    条款28:避免返回handles指向对象内部成分 条款29:为“异常安全”而努力是值得的 条款30:透彻了解inlining的里里外外 条款31:将文件间的编译依存关系降至最低 6.继承与面向对象设计 条款32:确定你的public...

    GUI_handles.zip_GUI_handles_GUI_handles.zip _MATLAB GUI源代码_Matla

    在MATLAB GUI中,"handles"是一个关键概念,它是一种数据结构,存储了GUI组件(如按钮、文本框、图像等)的信息。每个GUI组件都有一个唯一的句柄,这使得程序员可以通过句柄来访问和控制组件的属性和行为。例如,你...

    MATLAB GUI教学视频1:简单的文本框数据传递_GUI传递_matlab_GUI_

    例如,`get(handles.inputText,'String')`将获取名为`inputText`的文本框中的字符串数据。`handles`是一个全局变量,包含了所有GUI组件的句柄,使得我们可以访问和修改它们的属性。 处理数据后,我们使用`set`函数...

    leaked-handles:检测节点中泄漏的任何句柄

    require ( "leaked-handles" ) ; 示例输出。 no of handles 1 timer handle (`setTimeout(any, 1000)`) timer handle leaked at one of: at Test.t (/home/raynos/uber/leaked-handles/test/leak-timer.js:10:...

    Runtime Transform Handles

    在Unity引擎中,"Runtime Transform Handles"是一种高级的交互技术,允许用户在运行时通过直观的手柄来操纵场景中的对象,实现对物体的平移、缩放和旋转等操作。这种技术广泛应用于游戏开发、虚拟现实(VR)应用以及...

    flex-object-handles.zip_flex

    在Flex开发中,"flex-object-handles.zip_flex"这个压缩包可能包含了关于如何操作和交互Flex中的对象,特别是涉及到对象的移动、编译、放大和缩小功能的代码示例或教程。Flex是一种基于ActionScript和MXML的开源框架...

    gui之间数据传递我的一点经验总结-在不同的GUI之间共享数据(我的一点经验).doc

    通过将`handles`结构作为参数传递,以及在回调函数中使用`varargin`和`varargout`,我们可以轻松地实现GUI间的交互和数据交换。这种方法不仅方便,而且保持了代码的整洁性和可维护性,对于MATLAB GUI编程是非常实用...

    Matlab Gui 编程 数据传递

    使用`handles`和`guidata`可以实现在GUI的不同部分间共享数据,但需要谨慎管理`handles`结构的复杂性,避免数据冲突。 在实际应用中,根据需要传递的数据的复杂性以及GUI设计的规模,可以选择最适合的方法来处理...

    关于Unhandled event loop exception No more handles的两种解决方案

    ### 关于Unhandled event loop exception No more handles的两种解决方案 在使用Eclipse开发工具的过程中,有时会遇到一个较为棘刺的问题——出现“Unhandled event loop exception No more handles”的错误提示。...

    Runtime-Transform-Handles可用于Unity场景编辑的插件

    Runtime_Transform_Handles可用于Unity场景编辑的插件

    Runtime Transform Handles,可再unity运行时拖拽旋转物体,可用于制作场景编辑器等功能

    Runtime Transform Handles,可再unity运行时拖拽旋转物体,可用于制作场景编辑器等功能

    matlab GUI 多界面数据传递的实例

    此外,还可以考虑使用全局变量或者工作空间变量来辅助数据传递,但这种方法可能会导致数据管理复杂,因此在设计GUI时应尽量避免。 在压缩包文件"matlab GUI 多界面数据传递实例"中,你可以找到具体的代码示例,包括...

    MATLAB GUIDE程序设计参数在内部函数间及窗口间传递方式研究.pdf

    handles结构体用于存储GUI组件的状态信息,当需要在不同窗口间传递数据时,可以通过更新***s结构体中的数据,然后使用guidata函数来更新GUI窗口的相关状态。例如,在弹出菜单的callback函数中,我们可以设置handles...

    flex objecthandles一个很不错的拖拽伸缩控件

    在Flex编程领域,ObjectHandles是一个非常实用的组件,尤其对于新手开发者来说,它提供了一种简单易用的方式来实现拖拽和伸缩功能。这个组件能够帮助用户交互地调整对象的位置和大小,使得UI设计变得更加灵活和动态...

    ObjectHandles-2.0.0008

    《ObjectHandles-2.0.0008:图片缩放操作详解》 在IT行业中,图像处理是一项至关重要的技术,广泛应用于各种领域,如设计、摄影、数据分析等。ObjectHandles-2.0.0008是一款专门针对图片进行缩放操作的工具,其版本...

    (完整word版)MATLABGUI数据传递总结.pdf

    例如,如果只是在GUI内部的控件之间传递数据,`userdata`或`handles`结构体可能是最佳选择。而如果涉及到多个独立的GUI或需要在不同工作空间之间共享数据,全局变量、文件存储或函数参数传递可能更为合适。需要注意...

    filehandles:filehandles是一个文件句柄管理器,可让您从不同的文件源生成文件句柄-python source file

    filehandles软件包是一个Python库,它通过从目录,zip归档文件,tar归档文件,文件的URL地址等中删除用于打开文件的模板代码,从而简化了文件处理过程。已处理。 链接 filehandles @ filehandles @ 安装 该file...

    objecthandles_demo.rar

    标题“objecthandles_demo.rar”指的是一个包含有关ObjectHandles功能的示例或教程的压缩文件。ObjectHandles在IT行业中通常指的是在图形用户界面(GUI)设计工具或编程环境中,用于直观地操纵和调整对象属性的交互...

    MATLAB图形界面编程方法论总结 MATLAB的GUI数据传递总结 共16页.pdf

    这是一种非常灵活的方法,尤其适合在GUI内部的不同组件间传递数据。 **优点:** - 可以存储不同类型的数据。 - 灵活且易于使用。 **缺点:** - 如果大量使用可能会使代码难以维护。 - 需要手动管理数据。 **示例...

Global site tag (gtag.js) - Google Analytics