You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.21 16:36:01