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

如何正确交换含引用成员的foo类对象?std::swap失效问题求解

解决带引用成员类的std::swap异常问题

我刚折腾了一整天解决了一个类似的bug,正好碰到你这个场景——带引用成员的foo类用std::swap后出现了异常结果,先给你拆解问题根源,再给你正确的解决方案。

问题根源分析

std::swap的默认实现逻辑是:创建临时对象,通过拷贝构造和赋值操作完成交换。但你的foo类里的operator=只是把引用指向的值做了赋值(也就是让this->i_指向的变量等于that.i_指向的变量),而引用本身一旦绑定就无法更改指向。

当你调用std::swap(f1, f2)时,默认流程大概是这样:

  1. 创建临时foo对象tmp = f1(tmp的引用指向x)
  2. f1 = f2(f1的引用还是指向x,但把x的值改成了y的值100)
  3. f2 = tmp(f2的引用还是指向y,但把y的值改成了tmp引用的x的值——也就是已经变成100的x)
    最后x和y都变成100,两个foo对象的引用自然都输出100,这就是你看到的异常结果。

正确的交换方案

因为引用无法重新绑定,我们需要实现的是交换两个foo对象引用指向的变量的值,而不是交换foo对象本身的引用成员。我们可以为foo类自定义一个友元swap函数,利用ADL(参数依赖查找)让编译器优先使用这个自定义版本:

修改后的foo类代码

struct foo {
    inline foo(int& i) : i_(i) { }
    inline foo& operator=(const foo& that) {
        if (this != &that) {
            i_ = that.i_; // 保持原有赋值逻辑:拷贝引用指向的值
        }
        return *this;
    }
    // 自定义swap函数:交换两个foo对象引用指向的int变量的值
    inline friend void swap(foo& lhs, foo& rhs) noexcept {
        std::swap(lhs.i_, rhs.i_); // 这里交换的是int值,而非引用本身
    }
    inline friend std::ostream& operator<<(std::ostream& os, const foo& f) {
        os << f.i_;
        return os;
    }
private:
    foo();
    int& i_;
};

修改后的运行结果

当你用原来的测试代码运行时,结果会变成符合预期的:

before swapping
x = 10
y = 100
f1 = 10
f2 = 100
after swapping
x = 100
y = 10
f1 = 100
f2 = 10

重要提醒

std::swap并非通用解决方案:

  • 它的默认实现依赖于类的拷贝构造和赋值运算符,对于包含引用、指针、动态资源的类,默认swap往往不符合业务逻辑,甚至会导致错误。
  • 当你的类包含特殊成员(比如引用、需要手动管理的资源)时,一定要自定义合适的swap函数,确保交换逻辑符合你的预期。

内容的提问来源于stack exchange,提问作者Ngoc Linh

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:43:14