14-应该和不应该
12.3.1 应该和不应该
下面的摘要包含了两个不正确的示例(指出什么是不应当做的)以及一个良好的构造函数示例:
String::String()
{
str = "default string"; // oops, no new []
len = std::strlen(str);
}
String::String(const char * s)
{
len = std::strlen(s);
str = new char; // oops, no []
std::strcpy(str, s); // oops, no room
}
String::String(const String & st)
{
len = st.len;
str = new char[len + 1]; // good, allocate space
std::strcpy(str, st.str); // good, copy value
}
第一个构造函数没有使用new来初始化str。对默认对象调用析构函数时,析构函数使用delete来释放str。对不是使用new初始化的指针使用delete时,结果将是不确定的,并可能是有害的。可将该构造函数修改为下面的任何一种形式:
String::String()
{
len = 0;
str = new char[1]; // uses new with []
str[0] = '\0';
}
String::String()
{
len = 0;
str = 0; // or, with C++11, str = nullptr;
}
String::String()
{
static const char * s = "C++"; // initialized just once
len = std::strlen(s);
str = new char[len + 1]; // uses new with []
std::strcpy(str, s);
}
摘录中的第二个构造函数使用了new,但分配的内存量不正确。因此,new返回的内存块只能保存一个字符。试图将过长的字符串复制到该内存单元中,将导致内存问题。另外,这里使用的new不带中括号,这与另一个构造函数的正确格式不一致。
第三个构造函数是正确的。
最后,下面的析构函数无法与前面的构造函数正常地协同工作:
String::~String()
{
delete str; // oops, should be delete [] str;
}
该析构函数未能正确地使用delete。由于构造函数创建的是一个字符数组,因此析构函数应该删除一个数组。