C++自定义string类用户输入与赋值初始化输出结果不一致问题
问题根因
你碰到的输出差异和string类实现本身无关,是C++的即时求值规则导致的:
- 直接赋值场景下,你先完成a、b的赋值才执行
a + b计算c的结果,所以得到的是拼接后的正常字符串。 - 用户输入场景下,你在a、b还处于默认构造的空字符串状态时就执行了
a + b生成了c,后续修改a、b的内容不会反向更新已经生成的c,自然输出为空。
你提到的不想在输入后再给c赋值,本质是要实现惰性求值逻辑:c = a + b仅记录拼接关系,真正要用到c的内容时才实时计算拼接结果。
现有代码的已知bug修复
在实现惰性求值前,先修复现有代码的几个严重问题:
- 析构函数错误:你用
new[]分配字符数组,析构里应该用delete[] s而不是delete s,否则会触发内存泄漏甚至运行崩溃。 - 无效的
operator=(const char&)重载:这个重载逻辑错误,取单个char的地址当作C风格字符串处理会触发野指针访问,没用的话直接删掉该重载即可。 operator+逻辑缺失:现有拼接逻辑没有主动给结果字符串末尾补\0,虽然你是按size拷贝,但最好显式补全避免未定义行为。
惰性求值实现方案
你可以通过代理类实现拼接表达式的惰性计算,修改点如下:
1. 新增拼接代理类
在custom_string.h的string类定义前新增:
class string; // 拼接表达式代理类,仅记录拼接关系不实际计算 struct StringConcatExpr { const string& left; const string& right; StringConcatExpr(const string& a, const string& b) : left(a), right(b) {} // 主动求值为string的方法 operator string() const; };
2. 修改operator+的返回类型
把原来的operator+替换为:
StringConcatExpr operator+(const string& a, const string& b) { return StringConcatExpr(a, b); }
3. 实现代理类到string的转换逻辑
在string类的方法实现部分添加:
StringConcatExpr::operator string() const { if (left.s == nullptr ) { return right; } if (right.s == nullptr ) { return left; } string t; size_t k = 0; size_t l = 0; t.size = (left.size + right.size) - 1; t.s = new char[t.size]; while (left.s[k] != '\0' && k < left.size && k < t.size) { t.s[k] = left.s[k]; k++; } while (k < t.size && l < right.size) { t.s[k] = right.s[l]; k++; l++; } // 显式补末尾结束符 t.s[t.size - 1] = '\0'; return t; }
4. 适配需要触发求值的接口
修改输出、取长度等接口支持直接接收代理类,实现透明使用:
std::ostream& operator << (std::ostream& os, const StringConcatExpr& expr) { os << string(expr).output(); return os; } // 原有输出运算符参数加const更规范 std::ostream& operator << (std::ostream& os, const string& source) { os << source.output(); return os; } // 给代理类加length方法 unsigned int length(const StringConcatExpr& expr) { return string(expr).length(); }
5. 修改main中c的定义
把c的类型改成代理类即可,不需要在输入后重新赋值:
int main() { string a; string b; // 这里c是代理类,仅记录a和b的引用,不实际计算 StringConcatExpr c = a + b; std::cout << "Input a string: " << std::endl; std::cin >> a; std::cout << "Input b string: " << std::endl; std::cin >> b; // 输出时才触发计算,用的是最新的a、b值 std::cout << "C string is: " << c << std::endl; std::cout << "Length of C string is: " << length(c) << std::endl; system("pause"); return 0; }
注意事项
惰性求值的前提是你要保证参与拼接的a、b两个字符串的生命周期比代理类c更长,否则会出现悬垂引用导致崩溃。如果你的使用场景中a、b会提前销毁,还是建议用即时求值的方案,在输入完成后再计算c的值。
内容的提问来源于stack exchange,提问作者Eureka
相关产品推荐
相关产品推荐

