string模拟实现中出现的个别问题:下述string类没有显式定义其拷贝构造函数与赋值运算符重载,此时编译器会合成默认的,当用s1构造s2时,编译器会调用默认的拷贝构造。最终导致的问题是,s1、s2共用同一块内存空间,在释放时同一块空间被释放多次而引起程序崩溃,这种拷贝方式,称为浅拷贝。
浅拷贝:也称位拷贝,编译器只是将对象中的值拷贝过来。如果对象中管理资源,最后就会导致多个对象共享同一份资源,当一个对象销毁时就会将该资源释放掉,而此时另一些对象不知道该资源已经被释放,以为还有效,所以 当继续对资源进项操作时,就会发生发生了访问违规。
深拷贝:如果一个类中涉及到资源的管理,其拷贝构造函数、赋值运算符重载以及析构函数必须要显式给出。对于上述这种情况,在C++中给出了深拷贝的方法。
//构造函数
String(const String& s)
{
m_data = new char[strlen(s.m_data) + 1];
strcpy(m_data, s.m_data);
}
//赋值函数
String& operator=(const String& s)
{
if (this != &s);
{
delete[]m_data;
m_data = new char[strlen(s.m_data) + 1];
strcpy(m_data, s.m_data);
}
return *this;
}
但是在构造函数与赋值运算符重载时深拷贝也是最好的选择吗?并不是!在赋值函数中被释放了的空间并不一定可以再次申请成功,针对此情况有两种解决方式:
//赋值函数
String& operator=(const String& s)
{
if (this != &s);
{
delete[]m_data;
m_data = new char[strlen(s.m_data) + 1]; //释放了之后 不一定能在申请成功
strcpy(m_data, s.m_data);
//改进后的方法(1)
char* new_data = new char[strlen(s.m_data) + 1];
strcpy(new_data, s.m_data);
delete[]m_data;
m_data = new_data;
}
return *this;
}
//方法(2)
String& operator=(const String& s)
{
if (this != &s)
{
//这里的空间通过临时对象释放的
String Tmp(s); //构建一个临时对象
char* tmp_data = m_data;
m_data = Tmp.m_data;
Tmp.m_data = tmp_data;
}
return *this;
}
string的部分实现:
//string模拟的实现
class String
{
public:
//构造函数
String(const char* str = " ")
{
m_data = new char[strlen(str) + 1];
strcpy(m_data, str);
}
//构造函数
String(const String& s)
{
m_data = new char[strlen(s.m_data) + 1];
strcpy(m_data, s.m_data);
}
//赋值函数
String& operator=(const String& s)
{
if (this != &s)
{
//这里的空间通过临时对象释放的
String Tmp(s); //构建一个临时对象
char* tmp_data = m_data;
m_data = Tmp.m_data;
Tmp.m_data = tmp_data;
}
return *this;
}
//析构函数
~String()
{
if (m_data)
{
delete[]m_data;
m_data = nullptr;
}
}
private:
char* m_data;
};
void main()
{
String s1 = "abc";
String s2 = "xyz";
s2 = s1;
}
部分OJ题练习:
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
//将字符串转化为统一的大小写
void main()
{
string str = "ABC";
transform(str.begin(), str.end(), str.begin(), tolower);
}
//字符串转化为整形
void main()
{
const char* str = "1230";
int value = atoi(str); //通过atoi来转换
}
//字符串反转
void Reverse(string& s)
{
int start = 0;
int end = s.size() - 1;
while (start < end)
{
char tmp = s[start];
s[start] = s[end];
s[end] = tmp;
++start;
--end;
}
}
void main()
{
string s = "abcxyz";
Reverse(s);
reverse(s.begin(), s.end()); //C++的用法 直接反转
cout << s << endl;
}
//字符串相加
class Solution
{
public:
string addStrings(string num1, string num2)
{
reverse(num1.begin(), num1.end());
reverse(num2.begin(), num2.end());
int i, j;
i = j = 0;
int sign = 0;//进位
string result;
int sum = 0;
while (i < num1.size() && j < num2.size())
{
sum = num1[i] - '0' + num2[j] - '0' + sign;
if (sum >= 10)
{
sign = 1;
sum -= 10;
}
else
sign = 0;
result.push_back(sum + '0');
i++;
j++;
}
while (i < num1.size())
{
sum = num1[i] - '0' + sign;
if (sum >= 10)
{
sum -= 10;
sign = 1;
}
else
sign = 0;
result.push_back(sum + '0');
i++;
}
while (j < num2.size())
{
sum = num2[j] - '0' + sign;
if (sum >= 10)
{
sum -= 10;
sign = 1;
}
else
sign = 0;
result.push_back(sum + '0');
j++;
}
if (sign > 0)
result.push_back(sign + '0');
reverse(result.begin(), result.end());
return result;
}
};
//字符串中的第一个唯一字符
class Solution {
public:
int firstUniqChar(string s) //暴力求解法
{
int j;
for (int i = 0;i < s.size();++i)
{
for (j = 0;j < s.size();++j)
{
if (j == i)
continue;
if (s[j] == s[i])
break;
}
if (j >= s.size())
return i;
}
return -1;
}
};
class Solution {
public:
int firstUniqChar(string s) //通过hash表来查找
{
//0~255 hash[0]~hash[255]
int hash[256] = { 0 };
for (int i = 0;i < s.size();++i)
hash[s[i]]++;
for (int i = 0;i < s.size();++i)
{
if (hash[s[i]] == 1)
return i;
}
return -1;
}
};
//字符串最后一个单词的长度
int GetLengthLastWord(string& str)
{
int pos = str.rfind(' ');
if (pos == string::npos)
return str.size();
return str.size() - pos - 1;
}
void main()
{
string str;
getline(cin, str);
cout << GetLengthLastWord(str);
}
//判断字符串是否回文
class Solution {
public:
bool IsLetterOrDig(char ch)
{
if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9'))
return true;
return false;
}
bool isPalindrome(string s)
{
if (s.size() <= 1)
return true;
transform(s.begin(), s.end(), s.begin(), toupper); //将字符串统一转化为大写
int left = 0;
int right = s.size() - 1;
while (left < right)
{
while (left < right && !IsLetterOrDig(s[left]))
left++;
while (right > left && !IsLetterOrDig(s[right]))
right--;
if (s[left] != s[right])
return false;
left++;
right--;
}
return true;
}
};