本节书摘来自异步社区出版社《C++面向对象高效编程(第2版)》一书中的第4章,第4.9节,作者: 【美】Kayshav Dattatri,更多章节内容可以访问云栖社区“异步社区”公众号查看。
4.9 分析
C++面向对象高效编程(第2版)
TString类对象内部用一个指针和一个_length数据成员表示。默认构造函数将_length和_str指针都设置为0。_length数据成员是获取保存在字符串中的字符数目的一种方法。无论何时修改TString类对象中的字符数目,都会即时更新_length。
TString::TString(const char* arg)
在分配内存后从arg中复制字符到字符串对象中,然后正确设置_length。
TString::TString(char c)
用单个字符建立一个字符串对象。
TString::TString(cost TString& arg)
是复制构造函数,它执行深复制。首先,为arg指定的字符分配内存,然后复制所有字符。
TString::operator=(const TString& arg)
是一个赋值操作符,它进行了一些优化。如果this的_length大于arg的,那么只需进行复制操作。否则,将删除_str所指向的内存(无用单元收集),然后分配一段新内存,再复制字符。
TString:operator=(const char* s)
是另一个赋值操作符,它允许客户将字符数组赋给一个现有TString类对象,自动进行内存管理。
TString::operator=(char charToAssign)
还是一个赋值操作符,它允许客户将单个字符赋给一个现有的TString类对象,自动进行内存管理。
TString::Size()
返回字符串的大小(即储存的字符数目)。
TString::operator+=(const TString& arg)
是一个级联操作符。该操作将arg中的字符附在this中的字符后面。它为组合的字符串分配内存,然后复制字符。注意,不能修改arg。这个实现可以让诸如a +=a这样的表达式正常运行。
operator+(const TString& first, const TString& second)
以非成员函数的方式实现了加法操作符,原因将在第8章的操作符重载中讨论。在本章的讨论中,它是否为成员函数并不重要。该操作符在实现中使用了operator+=。
其实,加法操作符也可以这样写:
TString operator+(const TString& first, const TString& second)[ 注意,operator+应该按值返回结果,绝不会按引用或指针返回。我们将在后面介绍操作符重载的章节中分析这样做的原因。]
{
TString result;
result = first;
result += second; // 调用operator+=成员函数
return result;
}```
但是,这样效率太低。我们用默认构造函数创建了一个新字符串对象result,接下来给它赋值,然后在它后面加上second。注意,赋值操作将覆盖result中的值。为何不直接用复制构造函数创建对象result?这就是实现中(p.158中的加法操作符)所完成的工作。原始代码调用了复制构造函数和operator+=,而上面的代码调用了默认构造函数、赋值操作符和operator+=。很明显,原始实现的效率更高。许多成员函数中都会出现类似的情况。要记住,无论何时创建新对象又需要为其赋值时,都应检查是否可以用复制构造函数直接创建对象,这样的实现效率更高。
`operator==(const TString& first, const TString& second)`是一个比较操作符,以字符串中的字符词汇为基础进行比较。我们将该操作符作为非成员函数来实现,所有其他关系操作符的实现都与此类似。
`TString::operator()(unsigned n)`是一个子字符(sub-char)操作符,它返回下标为n的字符。这没什么特别。
`TString::operator[](unsigned n)`是一个下标操作符。它允许将TString类对象作为字符数组使用。注意,该操作符返回对const字符的引用。这确保字符串中的字符不能通过返回的引用来修改。
`TString::ToLower()`是一个辅助方法。它允许用户将字符串中的字符从大写形式改为小写形式。ToUpper与这个方法相反。
`TString::operator()(unsigned posn, unsigned len)`是一个子串(substring)操作符。它返回从posn的第一个字符开始往后len个字符的子串。注意,新字符串对象按值返回。
其他成员函数不言自明。输入/输出操作符、operator<<和operator>>将在第7章中详细讨论。
如此详细地讨论TString类,目的不是学习C++语法,而是为了思考下面解释的内容。
上面的代码中存在一个小问题(或者说是bug)。_length数据成员追踪_str中字符的数目,但不是已分配内存的原始大小。因此,如果创建一个可容纳100个字符的TString类对象,然后将包含10个字符的字符串赋给它,则_length数据成员为10。即使_str指向可容纳100个字符的内存块,其实只使用了前10个字符,剩下的全浪费了。如果我们知道要分配多少空间和使用有多少空间就好了。你能否在保证无内存泄漏的前提下解决这个问题?